From 61636b7ccf9cfda5b58dcd7791a7c9668c44074a Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Wed, 10 Jun 2026 16:34:35 +0530 Subject: [PATCH 1/8] feat(infra): restructure modules to GSA-compatible data structure Align infra/avm/modules and infra/bicep/modules folder structure with the unified GSA module pattern from agentic-applications repo. Added module categories: - security/ (key-vault) - fabric/ (fabric-capacity) Added modules within existing categories: - ai/: ai-foundry-connection, ai-foundry-model-deployment, ai-foundry-project, ai-services, existing-project-setup - compute/: app-service-plan, app-service, container-app-environment, container-app, container-instance, function-app, kubernetes, maintenance-configuration, proximity-placement-group, virtual-machine - data/: app-configuration, cosmos-db-nosql, event-grid, event-hub, postgresql-flexible-server, sql-database, storage-account - identity/: cross-scope-role-assignment, role-assignments - monitoring/: app-insights, data-collection-rule, portal-dashboard - networking/: bastion-host, private-dns-zone, private-endpoint Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../modules/ai/ai-foundry-connection.bicep | 84 +++ .../ai/ai-foundry-model-deployment.bicep | 64 +++ infra/avm/modules/ai/ai-foundry-project.bicep | 135 +++++ infra/avm/modules/ai/ai-foundry.bicep | 421 +++++++++++++++ infra/avm/modules/ai/ai-search.bicep | 121 +++++ infra/avm/modules/ai/ai-services.bicep | 121 +++++ .../modules/ai/existing-project-setup.bicep | 50 ++ .../avm/modules/ai/modules/dependencies.bicep | 479 ++++++++++++++++++ .../modules/ai/modules/keyVaultExport.bicep | 43 ++ infra/avm/modules/ai/modules/project.bicep | 62 +++ .../modules/compute/app-service-plan.bicep | 67 +++ infra/avm/modules/compute/app-service.bicep | 115 +++++ .../compute/container-app-environment.bicep | 95 ++++ infra/avm/modules/compute/container-app.bicep | 105 ++++ .../modules/compute/container-instance.bicep | 120 +++++ .../modules/compute/container-registry.bicep | 104 ++++ infra/avm/modules/compute/function-app.bicep | 95 ++++ infra/avm/modules/compute/kubernetes.bicep | 158 ++++++ .../compute/maintenance-configuration.bicep | 84 +++ .../compute/proximity-placement-group.bicep | 51 ++ .../avm/modules/compute/virtual-machine.bicep | 157 ++++++ .../avm/modules/data/app-configuration.bicep | 98 ++++ infra/avm/modules/data/cosmos-db-mongo.bicep | 137 +++++ infra/avm/modules/data/cosmos-db-nosql.bicep | 146 ++++++ infra/avm/modules/data/event-grid.bicep | 65 +++ infra/avm/modules/data/event-hub.bicep | 92 ++++ .../data/postgresql-flexible-server.bicep | 148 ++++++ infra/avm/modules/data/sql-database.bicep | 140 +++++ infra/avm/modules/data/storage-account.bicep | 135 +++++ .../avm/modules/fabric/fabric-capacity.bicep | 72 +++ .../cross-scope-role-assignment.bicep | 37 ++ .../modules/identity/managed-identity.bicep | 49 ++ .../modules/identity/role-assignments.bicep | 280 ++++++++++ .../avm/modules/monitoring/app-insights.bicep | 76 +++ .../monitoring/data-collection-rule.bicep | 149 ++++++ .../modules/monitoring/log-analytics.bicep | 90 ++++ .../modules/monitoring/portal-dashboard.bicep | 53 ++ .../avm/modules/networking/bastion-host.bicep | 85 ++++ .../modules/networking/private-dns-zone.bicep | 40 ++ .../modules/networking/private-endpoint.bicep | 52 ++ .../modules/networking/virtual-network.bicep | 303 +++++++++++ infra/avm/modules/security/key-vault.bicep | 109 ++++ .../modules/ai/ai-foundry-connection.bicep | 84 +++ .../ai/ai-foundry-model-deployment.bicep | 66 +++ .../bicep/modules/ai/ai-foundry-project.bicep | 111 ++++ infra/bicep/modules/ai/ai-foundry.bicep | 74 +++ .../bicep/modules/ai/ai-search-identity.bicep | 65 +++ infra/bicep/modules/ai/ai-search.bicep | 97 ++++ infra/bicep/modules/ai/ai-services.bicep | 87 ++++ .../modules/ai/existing-project-setup.bicep | 51 ++ .../modules/compute/app-service-plan.bicep | 60 +++ infra/bicep/modules/compute/app-service.bicep | 111 ++++ .../compute/container-app-environment.bicep | 63 +++ .../bicep/modules/compute/container-app.bicep | 117 +++++ .../modules/compute/container-instance.bicep | 119 +++++ .../modules/compute/container-registry.bicep | 75 +++ .../bicep/modules/compute/function-app.bicep | 100 ++++ infra/bicep/modules/compute/kubernetes.bicep | 134 +++++ .../modules/data/app-configuration.bicep | 63 +++ .../bicep/modules/data/cosmos-db-mongo.bicep | 114 +++++ .../bicep/modules/data/cosmos-db-nosql.bicep | 90 ++++ infra/bicep/modules/data/event-grid.bicep | 81 +++ infra/bicep/modules/data/event-hub.bicep | 62 +++ .../data/postgresql-flexible-server.bicep | 133 +++++ infra/bicep/modules/data/sql-database.bicep | 115 +++++ .../bicep/modules/data/storage-account.bicep | 101 ++++ .../modules/fabric/fabric-capacity.bicep | 72 +++ .../cross-scope-role-assignment.bicep | 37 ++ .../modules/identity/managed-identity.bicep | 43 ++ .../modules/identity/role-assignments.bicep | 350 +++++++++++++ .../modules/monitoring/app-insights.bicep | 72 +++ .../modules/monitoring/log-analytics.bicep | 58 +++ .../modules/monitoring/portal-dashboard.bicep | 49 ++ infra/bicep/modules/security/key-vault.bicep | 81 +++ 74 files changed, 8022 insertions(+) create mode 100644 infra/avm/modules/ai/ai-foundry-connection.bicep create mode 100644 infra/avm/modules/ai/ai-foundry-model-deployment.bicep create mode 100644 infra/avm/modules/ai/ai-foundry-project.bicep create mode 100644 infra/avm/modules/ai/ai-foundry.bicep create mode 100644 infra/avm/modules/ai/ai-search.bicep create mode 100644 infra/avm/modules/ai/ai-services.bicep create mode 100644 infra/avm/modules/ai/existing-project-setup.bicep create mode 100644 infra/avm/modules/ai/modules/dependencies.bicep create mode 100644 infra/avm/modules/ai/modules/keyVaultExport.bicep create mode 100644 infra/avm/modules/ai/modules/project.bicep create mode 100644 infra/avm/modules/compute/app-service-plan.bicep create mode 100644 infra/avm/modules/compute/app-service.bicep create mode 100644 infra/avm/modules/compute/container-app-environment.bicep create mode 100644 infra/avm/modules/compute/container-app.bicep create mode 100644 infra/avm/modules/compute/container-instance.bicep create mode 100644 infra/avm/modules/compute/container-registry.bicep create mode 100644 infra/avm/modules/compute/function-app.bicep create mode 100644 infra/avm/modules/compute/kubernetes.bicep create mode 100644 infra/avm/modules/compute/maintenance-configuration.bicep create mode 100644 infra/avm/modules/compute/proximity-placement-group.bicep create mode 100644 infra/avm/modules/compute/virtual-machine.bicep create mode 100644 infra/avm/modules/data/app-configuration.bicep create mode 100644 infra/avm/modules/data/cosmos-db-mongo.bicep create mode 100644 infra/avm/modules/data/cosmos-db-nosql.bicep create mode 100644 infra/avm/modules/data/event-grid.bicep create mode 100644 infra/avm/modules/data/event-hub.bicep create mode 100644 infra/avm/modules/data/postgresql-flexible-server.bicep create mode 100644 infra/avm/modules/data/sql-database.bicep create mode 100644 infra/avm/modules/data/storage-account.bicep create mode 100644 infra/avm/modules/fabric/fabric-capacity.bicep create mode 100644 infra/avm/modules/identity/cross-scope-role-assignment.bicep create mode 100644 infra/avm/modules/identity/managed-identity.bicep create mode 100644 infra/avm/modules/identity/role-assignments.bicep create mode 100644 infra/avm/modules/monitoring/app-insights.bicep create mode 100644 infra/avm/modules/monitoring/data-collection-rule.bicep create mode 100644 infra/avm/modules/monitoring/log-analytics.bicep create mode 100644 infra/avm/modules/monitoring/portal-dashboard.bicep create mode 100644 infra/avm/modules/networking/bastion-host.bicep create mode 100644 infra/avm/modules/networking/private-dns-zone.bicep create mode 100644 infra/avm/modules/networking/private-endpoint.bicep create mode 100644 infra/avm/modules/networking/virtual-network.bicep create mode 100644 infra/avm/modules/security/key-vault.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry-connection.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry-model-deployment.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry-project.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry.bicep create mode 100644 infra/bicep/modules/ai/ai-search-identity.bicep create mode 100644 infra/bicep/modules/ai/ai-search.bicep create mode 100644 infra/bicep/modules/ai/ai-services.bicep create mode 100644 infra/bicep/modules/ai/existing-project-setup.bicep create mode 100644 infra/bicep/modules/compute/app-service-plan.bicep create mode 100644 infra/bicep/modules/compute/app-service.bicep create mode 100644 infra/bicep/modules/compute/container-app-environment.bicep create mode 100644 infra/bicep/modules/compute/container-app.bicep create mode 100644 infra/bicep/modules/compute/container-instance.bicep create mode 100644 infra/bicep/modules/compute/container-registry.bicep create mode 100644 infra/bicep/modules/compute/function-app.bicep create mode 100644 infra/bicep/modules/compute/kubernetes.bicep create mode 100644 infra/bicep/modules/data/app-configuration.bicep create mode 100644 infra/bicep/modules/data/cosmos-db-mongo.bicep create mode 100644 infra/bicep/modules/data/cosmos-db-nosql.bicep create mode 100644 infra/bicep/modules/data/event-grid.bicep create mode 100644 infra/bicep/modules/data/event-hub.bicep create mode 100644 infra/bicep/modules/data/postgresql-flexible-server.bicep create mode 100644 infra/bicep/modules/data/sql-database.bicep create mode 100644 infra/bicep/modules/data/storage-account.bicep create mode 100644 infra/bicep/modules/fabric/fabric-capacity.bicep create mode 100644 infra/bicep/modules/identity/cross-scope-role-assignment.bicep create mode 100644 infra/bicep/modules/identity/managed-identity.bicep create mode 100644 infra/bicep/modules/identity/role-assignments.bicep create mode 100644 infra/bicep/modules/monitoring/app-insights.bicep create mode 100644 infra/bicep/modules/monitoring/log-analytics.bicep create mode 100644 infra/bicep/modules/monitoring/portal-dashboard.bicep create mode 100644 infra/bicep/modules/security/key-vault.bicep diff --git a/infra/avm/modules/ai/ai-foundry-connection.bicep b/infra/avm/modules/ai/ai-foundry-connection.bicep new file mode 100644 index 00000000..c3260e4d --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry-connection.bicep @@ -0,0 +1,84 @@ +// ============================================================================ +// Module: AI Foundry Project Connection (Single) +// Description: Creates a single connection on an AI Foundry project. +// Generic, reusable — call once per connection type from main.bicep. +// Supports any connection category (CognitiveSearch, AzureBlob, +// AppInsights, RemoteTool, etc.) via parameterized properties. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name of the AI Foundry project.') +param projectName string + +@description('Required. Solution name suffix used to generate the connection name.') +param solutionName string + +@description('Optional. Connection name. Defaults to lowercase category with solution suffix.') +param connectionName string = toLower('${category}-connection-${solutionName}') + +@description('Required. Connection category (e.g., CognitiveSearch, AzureBlob, AppInsights, RemoteTool).') +param category string + +@description('Required. Connection target (URL or resource ID).') +param target string + +@description('Required. Authentication type (e.g., AAD, ApiKey, ProjectManagedIdentity).') +param authType string + +@description('Optional. Whether the connection is shared to all project users.') +param isSharedToAll bool = true + +@description('Optional. Whether this is the default connection for its category.') +param isDefault bool = false + +@description('Optional. Connection metadata object.') +param metadata object = {} + +@secure() +@description('Optional. Credentials key (for ApiKey auth type).') +param credentialsKey string = '' + +// ============================================================================ +// Existing Resource References +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: aiServicesAccount + name: projectName +} + +// ============================================================================ +// Connection +// ============================================================================ +var baseProperties = { + category: category + target: target + authType: authType + isSharedToAll: isSharedToAll + metadata: metadata +} + +var optionalDefault = isDefault ? { isDefault: true } : {} +var optionalCredentials = !empty(credentialsKey) ? { credentials: { key: credentialsKey } } : {} + +resource connection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-12-01' = { + parent: aiProject + name: connectionName + properties: any(union(baseProperties, optionalDefault, optionalCredentials)) +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Connection name.') +output connectionName string = connection.name + +@description('Connection resource ID.') +output connectionId string = connection.id diff --git a/infra/avm/modules/ai/ai-foundry-model-deployment.bicep b/infra/avm/modules/ai/ai-foundry-model-deployment.bicep new file mode 100644 index 00000000..1c534fd8 --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry-model-deployment.bicep @@ -0,0 +1,64 @@ +// ============================================================================ +// Module: Model Deployment +// Description: Deploys a single AI model to an existing AI Services account. +// Called repetitively from main.bicep for each model in the array. +// Generic, reusable across GSAs. +// ============================================================================ + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name for this model deployment.') +param deploymentName string + +@description('Optional. Model format (e.g., OpenAI).') +param modelFormat string = 'OpenAI' + +@description('Required. Model name (e.g., gpt-4o, text-embedding-ada-002).') +param modelName string + +@description('Optional. Model version. Empty string means latest.') +param modelVersion string = '' + +@description('Optional. RAI policy name.') +param raiPolicyName string = 'Microsoft.Default' + +@description('Required. SKU name (e.g., Standard, GlobalStandard).') +param skuName string + +@description('Required. SKU capacity (tokens per minute in thousands).') +param skuCapacity int + +// ============================================================================ +// Model Deployment +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource modelDeployment 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { + parent: aiServicesAccount + name: deploymentName + properties: { + model: { + format: modelFormat + name: modelName + version: !empty(modelVersion) ? modelVersion : null + } + raiPolicyName: raiPolicyName + } + sku: { + name: skuName + capacity: skuCapacity + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Name of the deployed model.') +output name string = modelDeployment.name + +@description('Resource ID of the model deployment.') +output resourceId string = modelDeployment.id diff --git a/infra/avm/modules/ai/ai-foundry-project.bicep b/infra/avm/modules/ai/ai-foundry-project.bicep new file mode 100644 index 00000000..76671e96 --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry-project.bicep @@ -0,0 +1,135 @@ +// ============================================================================ +// Module: AI Foundry Project (Account + Project) +// Description: AVM wrapper for Azure AI Services account creation and +// AI Foundry project provisioning. Generic, reusable across GSAs. +// AVM Module: avm/res/cognitive-services/account +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-openai +// ============================================================================ + +@description('Required. Solution name suffix used to generate resource names.') +param solutionName string + +@description('Optional. Override name for the AI Services account. Defaults to aif-{solutionName}.') +param name string = 'aif-${solutionName}' + +@description('Optional. Override name for the AI Foundry project. Defaults to proj-{solutionName}.') +param projectName string = 'proj-${solutionName}' + +@description('Required. Azure region for the resources.') +param location string + +@description('Optional. Tags to apply to resources.') +param tags object = {} + +@description('Optional. SKU name for the AI Services account.') +param skuName string = 'S0' + +@description('Optional. Whether to disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Optional. Whether to allow project management (AI Foundry hub).') +param allowProjectManagement bool = true + +@description('Optional. Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Managed identity type for the resources.') +@allowed(['SystemAssigned', 'UserAssigned', 'SystemAssigned, UserAssigned', 'None']) +param identityType string = 'SystemAssigned' + +@description('Optional. Network ACLs default action.') +@allowed(['Allow', 'Deny']) +param networkAclsDefaultAction string = 'Allow' + +// --- WAF: Monitoring --- +@description('Optional. Diagnostic settings for the resource.') +param diagnosticSettings array? + +// --- WAF: Telemetry --- +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- Role Assignments --- +@description('Optional. Array of role assignments to create on the AI Services account.') +param roleAssignments array? + +// ============================================================================ +// AI Services Account (AVM Module) +// ============================================================================ +module aiServicesAccount 'br/public:avm/res/cognitive-services/account:0.14.2' = { + name: take('avm.res.cognitive-services.account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: skuName + kind: 'AIServices' + disableLocalAuth: disableLocalAuth + allowProjectManagement: allowProjectManagement + customSubDomainName: name + networkAcls: { + defaultAction: networkAclsDefaultAction + virtualNetworkRules: [] + ipRules: [] + } + publicNetworkAccess: publicNetworkAccess + managedIdentities: { + systemAssigned: true + } + diagnosticSettings: diagnosticSettings + deployments: [] + roleAssignments: roleAssignments + // Private endpoints deployed separately to avoid AccountProvisioningStateInvalid + privateEndpoints: [] + } +} + +// ============================================================================ +// AI Foundry Project +// ============================================================================ +resource aiServicesResource 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name + dependsOn: [aiServicesAccount] +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { + parent: aiServicesResource + name: projectName + location: location + tags: tags + kind: 'AIServices' + identity: { + type: identityType + } + properties: {} + dependsOn: [aiServicesAccount] +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the AI Services account.') +output resourceId string = aiServicesAccount.outputs.resourceId + +@description('Name of the AI Services account.') +output name string = aiServicesAccount.outputs.name + +@description('Endpoint of the AI Services account.') +output endpoint string = aiServicesAccount.outputs.endpoint + +@description('System-assigned identity principal ID of the AI Services account.') +output principalId string = aiServicesAccount.outputs.systemAssignedMIPrincipalId + +@description('Resource ID of the AI Foundry project.') +output projectResourceId string = aiProject.id + +@description('Name of the AI Foundry project.') +output projectName string = aiProject.name + +@description('AI Foundry project endpoint.') +output projectEndpoint string = aiProject.properties.endpoints['AI Foundry API'] + +@description('System-assigned identity principal ID of the project.') +output projectIdentityPrincipalId string = aiProject.identity.principalId diff --git a/infra/avm/modules/ai/ai-foundry.bicep b/infra/avm/modules/ai/ai-foundry.bicep new file mode 100644 index 00000000..4342f5f9 --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry.bicep @@ -0,0 +1,421 @@ +metadata name = 'Cognitive Services' +metadata description = 'This module deploys a Cognitive Service.' + +@description('Required. The name of Cognitive Services account.') +param name string + +@description('Optional: Name for the project which needs to be created.') +param projectName string + +@description('Optional: Description for the project which needs to be created.') +param projectDescription string + +param existingFoundryProjectResourceId string = '' + +@description('Required. Kind of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'AIServices' + 'AnomalyDetector' + 'CognitiveServices' + 'ComputerVision' + 'ContentModerator' + 'ContentSafety' + 'ConversationalLanguageUnderstanding' + 'CustomVision.Prediction' + 'CustomVision.Training' + 'Face' + 'FormRecognizer' + 'HealthInsights' + 'ImmersiveReader' + 'Internal.AllInOne' + 'LUIS' + 'LUIS.Authoring' + 'LanguageAuthoring' + 'MetricsAdvisor' + 'OpenAI' + 'Personalizer' + 'QnAMaker.v2' + 'SpeechServices' + 'TextAnalytics' + 'TextTranslation' +]) +param kind string + +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'C2' + 'C3' + 'C4' + 'F0' + 'F1' + 'S' + 'S0' + 'S1' + 'S10' + 'S2' + 'S3' + 'S4' + 'S5' + 'S6' + 'S7' + 'S8' + 'S9' +]) +param sku string = 'S0' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string? + +@description('Conditional. Subdomain name used for token-based authentication. Required if \'networkAcls\' or \'privateEndpoints\' are set.') +param customSubDomainName string? + +@description('Optional. A collection of rules governing the accessibility from specific network locations.') +param networkAcls object? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. List of allowed FQDN.') +param allowedFqdnList array? + +@description('Optional. The API properties for special APIs.') +param apiProperties object? + +@description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') +param disableLocalAuth bool = true + +import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The customer managed key definition.') +param customerManagedKey customerManagedKeyType? + +@description('Optional. The flag to enable dynamic throttling.') +param dynamicThrottlingEnabled bool = false + +@secure() +@description('Optional. Resource migration token.') +param migrationToken string? + +@description('Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists.') +param restore bool = false + +@description('Optional. Restrict outbound network access.') +param restrictOutboundNetworkAccess bool = true + +@description('Optional. The storage accounts for this resource.') +param userOwnedStorage array? + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityAllType? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Array of deployments about cognitive service accounts to create.') +param deployments deploymentType[]? + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +@description('Optional. Enable/Disable project management feature for AI Foundry.') +param allowProjectManagement bool? + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { + name: '46d3xbcp.res.cognitiveservices-account.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split(customerManagedKey.?keyVaultResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?keyVaultResourceId!, '/')[2], + split(customerManagedKey.?keyVaultResourceId!, '/')[4] + ) + + resource cMKKey 'keys@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName! + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[2], + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[4] + ) +} + +var useExistingService = !empty(existingFoundryProjectResourceId) + +resource cognitiveServiceNew 'Microsoft.CognitiveServices/accounts@2025-12-01' = if(!useExistingService) { + name: name + kind: kind + identity: identity + location: location + tags: tags + sku: { + name: sku + } + properties: { + allowProjectManagement: allowProjectManagement // allows project management for Cognitive Services accounts in AI Foundry - FDP updates + customSubDomainName: customSubDomainName + networkAcls: !empty(networkAcls ?? {}) + ? { + defaultAction: networkAcls.?defaultAction + virtualNetworkRules: networkAcls.?virtualNetworkRules ?? [] + ipRules: networkAcls.?ipRules ?? [] + } + : null + publicNetworkAccess: publicNetworkAccess != null + ? publicNetworkAccess + : (!empty(networkAcls) ? 'Enabled' : 'Disabled') + allowedFqdnList: allowedFqdnList + apiProperties: apiProperties + disableLocalAuth: disableLocalAuth + encryption: !empty(customerManagedKey) + ? { + keySource: 'Microsoft.KeyVault' + keyVaultProperties: { + identityClientId: !empty(customerManagedKey.?userAssignedIdentityResourceId ?? '') + ? cMKUserAssignedIdentity.properties.clientId + : null + keyVaultUri: cMKKeyVault.properties.vaultUri + keyName: customerManagedKey!.keyName + keyVersion: !empty(customerManagedKey.?keyVersion ?? '') + ? customerManagedKey!.?keyVersion + : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + } + } + : null + migrationToken: migrationToken + restore: restore + restrictOutboundNetworkAccess: restrictOutboundNetworkAccess + userOwnedStorage: userOwnedStorage + dynamicThrottlingEnabled: dynamicThrottlingEnabled + } +} + +var existingCognitiveServiceDetails = split(existingFoundryProjectResourceId, '/') + +resource cognitiveServiceExisting 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if(useExistingService) { + name: existingCognitiveServiceDetails[8] + scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) +} + +module cognitive_service_dependencies './modules/dependencies.bicep' = if(!useExistingService) { + params: { + projectName: projectName + projectDescription: projectDescription + name: cognitiveServiceNew.name + location: location + deployments: deployments + diagnosticSettings: diagnosticSettings + lock: lock + privateEndpoints: privateEndpoints + roleAssignments: roleAssignments + secretsExportConfiguration: secretsExportConfiguration + sku: sku + tags: tags + } +} + +module existing_cognitive_service_dependencies './modules/dependencies.bicep' = if(useExistingService) { + params: { + name: cognitiveServiceExisting.name + projectName: projectName + projectDescription: projectDescription + azureExistingAIProjectResourceId: existingFoundryProjectResourceId + location: location + deployments: deployments + diagnosticSettings: diagnosticSettings + lock: lock + privateEndpoints: privateEndpoints + roleAssignments: roleAssignments + secretsExportConfiguration: secretsExportConfiguration + sku: sku + tags: tags + } + scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) +} + +var cognitiveService = useExistingService ? cognitiveServiceExisting : cognitiveServiceNew + +@description('The name of the cognitive services account.') +output name string = useExistingService ? cognitiveServiceExisting.name : cognitiveServiceNew.name + +@description('The resource ID of the cognitive services account.') +output resourceId string = useExistingService ? cognitiveServiceExisting.id : cognitiveServiceNew.id + +@description('The resource group the cognitive services account was deployed into.') +output subscriptionId string = useExistingService ? existingCognitiveServiceDetails[2] : subscription().subscriptionId + +@description('The resource group the cognitive services account was deployed into.') +output resourceGroupName string = useExistingService ? existingCognitiveServiceDetails[4] : resourceGroup().name + +@description('The service endpoint of the cognitive services account.') +output endpoint string = useExistingService ? cognitiveServiceExisting.properties.endpoint : cognitiveService.properties.endpoint + +@description('All endpoints available for the cognitive services account, types depends on the cognitive service kind.') +output endpoints endpointType = useExistingService ? cognitiveServiceExisting.properties.endpoints : cognitiveService.properties.endpoints + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = useExistingService ? cognitiveServiceExisting.identity.principalId : cognitiveService.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = useExistingService ? cognitiveServiceExisting.location : cognitiveService.location + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.exportedSecrets : cognitive_service_dependencies.outputs.exportedSecrets + +@description('The private endpoints of the congitive services account.') +output privateEndpoints privateEndpointOutputType[] = useExistingService ? existing_cognitive_service_dependencies.outputs.privateEndpoints : cognitive_service_dependencies.outputs.privateEndpoints + +import { aiProjectOutputType } from './modules/project.bicep' +output aiProjectInfo aiProjectOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.aiProjectInfo : cognitive_service_dependencies.outputs.aiProjectInfo + +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for the private endpoint output.') +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The type for a cognitive services account deployment.') +type deploymentType = { + @description('Optional. Specify the name of cognitive service account deployment.') + name: string? + + @description('Required. Properties of Cognitive Services account deployment model.') + model: { + @description('Required. The name of Cognitive Services account deployment model.') + name: string + + @description('Required. The format of Cognitive Services account deployment model.') + format: string + + @description('Required. The version of Cognitive Services account deployment model.') + version: string + } + + @description('Optional. The resource model definition representing SKU.') + sku: { + @description('Required. The name of the resource model definition representing SKU.') + name: string + + @description('Optional. The capacity of the resource model definition representing SKU.') + capacity: int? + + @description('Optional. The tier of the resource model definition representing SKU.') + tier: string? + + @description('Optional. The size of the resource model definition representing SKU.') + size: string? + + @description('Optional. The family of the resource model definition representing SKU.') + family: string? + }? + + @description('Optional. The name of RAI policy.') + raiPolicyName: string? + + @description('Optional. The version upgrade option.') + versionUpgradeOption: string? +} + +@export() +@description('The type for a cognitive services account endpoint.') +type endpointType = { + @description('Type of the endpoint.') + name: string? + @description('The endpoint URI.') + endpoint: string? +} + +@export() +@description('The type of the secrets exported to the provided Key Vault.') +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The name for the accessKey1 secret to create.') + accessKey1Name: string? + + @description('Optional. The name for the accessKey2 secret to create.') + accessKey2Name: string? +} diff --git a/infra/avm/modules/ai/ai-search.bicep b/infra/avm/modules/ai/ai-search.bicep new file mode 100644 index 00000000..27f35bf6 --- /dev/null +++ b/infra/avm/modules/ai/ai-search.bicep @@ -0,0 +1,121 @@ +// ============================================================================ +// Module: AI Search +// Description: Deploys Azure AI Search with a two-step pattern: +// Step 1: Plain Bicep resource for fast initial creation (name, location, SKU) +// Step 2: AVM module update to enable managed identity & full configuration +// This reduces deployment time by making the resource available immediately +// while identity enablement proceeds separately. +// AVM Module: avm/res/search/search-service:0.12.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-cognitive-search +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +@minLength(3) +param solutionName string + +@description('Optional. Override name for the search service. Defaults to srch-{solutionName}.') +param name string = 'srch-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the search service.') +@allowed(['free', 'basic', 'standard', 'standard2', 'standard3', 'storage_optimized_l1', 'storage_optimized_l2']) +param skuName string = 'basic' + +@description('Number of replicas.') +param replicaCount int = 1 + +@description('Number of partitions.') +param partitionCount int = 1 + +@description('Hosting mode.') +@allowed(['Default', 'HighDensity']) +param hostingMode string = 'Default' + +@description('Semantic search tier.') +@allowed(['disabled', 'free', 'standard']) +param semanticSearch string = 'free' + +@description('Whether to disable local authentication.') +param disableLocalAuth bool = true + +@description('Managed identity type for the search service.') +param managedIdentityType string = 'SystemAssigned' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// --- WAF: Telemetry --- +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Private endpoint configurations.') +param privateEndpoints array = [] + +// --- Role Assignments --- +@description('Optional. Array of role assignments to create on the AI Search service.') +param roleAssignments array = [] + +// ============================================================================ +// Step 1: Initial resource creation (plain Bicep — fast) +// ============================================================================ +resource searchService 'Microsoft.Search/searchServices@2025-05-01' = { + name: name + location: location + sku: { + name: skuName + } +} + +// ============================================================================ +// Step 2: AVM update — enables identity & full configuration +// ============================================================================ +module searchServiceUpdate 'br/public:avm/res/search/search-service:0.12.0' = { + name: take('avm.res.search.update.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: skuName + replicaCount: replicaCount + partitionCount: partitionCount + hostingMode: hostingMode + semanticSearch: semanticSearch + disableLocalAuth: disableLocalAuth + publicNetworkAccess: publicNetworkAccess + managedIdentities: { + systemAssigned: managedIdentityType == 'SystemAssigned' + } + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + privateEndpoints: privateEndpoints + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + } + dependsOn: [ + searchService + ] +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the AI Search service.') +output resourceId string = searchService.id + +@description('Name of the AI Search service.') +output name string = searchService.name + +@description('Endpoint URL of the AI Search service.') +output endpoint string = 'https://${searchService.name}.search.windows.net' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = searchServiceUpdate.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/ai/ai-services.bicep b/infra/avm/modules/ai/ai-services.bicep new file mode 100644 index 00000000..7e27f49d --- /dev/null +++ b/infra/avm/modules/ai/ai-services.bicep @@ -0,0 +1,121 @@ +// ============================================================================ +// Module: Azure AI Services (Generic) +// Description: AVM wrapper for Cognitive Services — supports Content Safety, +// Speech, Computer Vision, Document Intelligence, and others. +// AVM Module: avm/res/cognitive-services/account:0.14.2 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name prefix for the resource (e.g., cs, speech, cv, docintel).') +param namePrefix string + +@description('The kind of Cognitive Service to deploy.') +@allowed([ + 'ContentSafety' + 'SpeechServices' + 'ComputerVision' + 'FormRecognizer' + 'TextAnalytics' + 'TextTranslation' + 'Face' + 'OpenAI' + 'AIServices' +]) +param kind string + +@description('Optional. Override name for the resource. Defaults to {namePrefix}-{solutionName}.') +param name string = '${namePrefix}-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = false + +@description('SKU for the Cognitive Services account.') +@allowed(['F0', 'S0', 'S1']) +param sku string = 'S0' + +@description('Custom subdomain name for the account.') +param customSubDomainName string = '' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Optional. Role assignments for the resource.') +param roleAssignments array = [] + +var effectiveSubDomain = !empty(customSubDomainName) ? customSubDomainName : name + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module aiService 'br/public:avm/res/cognitive-services/account:0.14.2' = { + name: take('avm.res.cognitive-services.${namePrefix}.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + kind: kind + sku: sku + customSubDomainName: effectiveSubDomain + disableLocalAuth: disableLocalAuth + managedIdentities: { systemAssigned: true } + publicNetworkAccess: publicNetworkAccess + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'account' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AI Services account.') +output name string = aiService.outputs.name + +@description('Resource ID of the AI Services account.') +output resourceId string = aiService.outputs.resourceId + +@description('Endpoint of the AI Services account.') +output endpoint string = aiService.outputs.endpoint + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = aiService.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/ai/existing-project-setup.bicep b/infra/avm/modules/ai/existing-project-setup.bicep new file mode 100644 index 00000000..7a396dcb --- /dev/null +++ b/infra/avm/modules/ai/existing-project-setup.bicep @@ -0,0 +1,50 @@ +// ============================================================================ +// Module: Existing AI Foundry Project Reference +// Description: References an existing AI Services account and project to +// retrieve their identities. No deployments, no connections. +// Use generic ai-foundry-connection and ai-foundry-model-deployment +// modules for those concerns. +// ============================================================================ + +@description('Required. The name of the existing Cognitive Services account.') +param name string + +@description('Required. The name of the existing AI project.') +param projectName string + +// ============================================================================ +// Existing Resource References +// ============================================================================ +resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: cognitiveService + name: projectName +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The principal ID of the AI Foundry system-assigned managed identity (empty if none).') +output aiFoundryPrincipalId string = cognitiveService.identity.?principalId ?? '' + +@description('The principal ID of the AI Project system-assigned managed identity (empty if none).') +output aiProjectPrincipalId string = aiProject.identity.?principalId ?? '' + +@description('The name of the AI Services account.') +output aiServicesAccountName string = cognitiveService.name + +@description('The name of the AI project.') +output aiProjectName string = aiProject.name + +@description('The endpoint URL for the Azure OpenAI service.') +output aiFoundryEndpoint string = 'https://${name}.openai.azure.com/' + +@description('The endpoint URL for the AI Foundry project.') +output projectEndpoint string = 'https://${name}.services.ai.azure.com/api/projects/${projectName}' + +@description('The resource ID of the AI Services account.') +output aiFoundryResourceId string = cognitiveService.id + diff --git a/infra/avm/modules/ai/modules/dependencies.bicep b/infra/avm/modules/ai/modules/dependencies.bicep new file mode 100644 index 00000000..55bb9ff7 --- /dev/null +++ b/infra/avm/modules/ai/modules/dependencies.bicep @@ -0,0 +1,479 @@ +@description('Required. The name of Cognitive Services account.') +param name string + +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'C2' + 'C3' + 'C4' + 'F0' + 'F1' + 'S' + 'S0' + 'S1' + 'S10' + 'S2' + 'S3' + 'S4' + 'S5' + 'S6' + 'S7' + 'S8' + 'S9' +]) +param sku string = 'S0' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Array of deployments about cognitive service accounts to create.') +param deployments deploymentType[]? + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional: Name for the project which needs to be created.') +param projectName string + +@description('Optional: Description for the project which needs to be created.') +param projectDescription string + +@description('Optional: Provide the existing project resource id in case if it needs to be reused') +param azureExistingAIProjectResourceId string = '' + +var builtInRoleNames = { + 'Cognitive Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68' + ) + 'Cognitive Services Custom Vision Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3' + ) + 'Cognitive Services Custom Vision Deployment': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5c4089e1-6d96-4d2f-b296-c1bc7137275f' + ) + 'Cognitive Services Custom Vision Labeler': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '88424f51-ebe7-446f-bc41-7fa16989e96c' + ) + 'Cognitive Services Custom Vision Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '93586559-c37d-4a6b-ba08-b9f0940c2d73' + ) + 'Cognitive Services Custom Vision Trainer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b' + ) + 'Cognitive Services Data Reader (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b59867f0-fa02-499b-be73-45a86b5b3e1c' + ) + 'Cognitive Services Face Recognizer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '9894cab4-e18a-44aa-828b-cb588cd6f2d7' + ) + 'Cognitive Services Immersive Reader User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b2de6794-95db-4659-8781-7e080d3f2b9d' + ) + 'Cognitive Services Language Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f07febfe-79bc-46b1-8b37-790e26e6e498' + ) + 'Cognitive Services Language Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7628b7b8-a8b2-4cdc-b46f-e9b35248918e' + ) + 'Cognitive Services Language Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8' + ) + 'Cognitive Services LUIS Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f72c8140-2111-481c-87ff-72b910f6e3f8' + ) + 'Cognitive Services LUIS Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18e81cdc-4e98-4e29-a639-e7d10c5a6226' + ) + 'Cognitive Services LUIS Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '6322a993-d5c9-4bed-b113-e49bbea25b27' + ) + 'Cognitive Services Metrics Advisor Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'cb43c632-a144-4ec5-977c-e80c4affc34a' + ) + 'Cognitive Services Metrics Advisor User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3b20f47b-3825-43cb-8114-4bd2201156a8' + ) + 'Cognitive Services OpenAI Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a001fd3d-188f-4b5d-821b-7da978bf7442' + ) + 'Cognitive Services OpenAI User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + ) + 'Cognitive Services QnA Maker Editor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f4cc2bf9-21be-47a1-bdf1-5c5804381025' + ) + 'Cognitive Services QnA Maker Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '466ccd10-b268-4a11-b098-b4849f024126' + ) + 'Cognitive Services Speech Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0e75ca1e-0464-4b4d-8b93-68208a576181' + ) + 'Cognitive Services Speech User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2dc8367-1007-4938-bd23-fe263f013447' + ) + 'Cognitive Services User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a97b65f3-24c7-4388-baec-2e87135dc908' + ) + 'Azure AI Developer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '64702f94-c441-49e6-a78b-ef80e0188fee' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +var enableReferencedModulesTelemetry = false + +resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name +} + +@batchSize(1) +resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = [ + for (deployment, index) in (deployments ?? []): { + parent: cognitiveService + name: deployment.?name ?? '${name}-deployments' + properties: { + model: deployment.model + raiPolicyName: deployment.?raiPolicyName + versionUpgradeOption: deployment.?versionUpgradeOption + } + sku: deployment.?sku ?? { + name: sku + capacity: sku.?capacity + tier: sku.?tier + size: sku.?size + family: sku.?family + } + } +] + +resource cognitiveService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: cognitiveService +} + +resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: cognitiveService + } +] + +module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.12.0' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}' + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: enableReferencedModulesTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: cognitiveService + } +] + +module secretsExport './keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[2], + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId!, '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'accessKey1Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey1Name + value: cognitiveService.listKeys().key1 + } + ] + : [], + contains(secretsExportConfiguration!, 'accessKey2Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey2Name + value: cognitiveService.listKeys().key2 + } + ] + : [] + ) + } +} + +module aiProject 'project.bicep' = if(!empty(projectName) || !empty(azureExistingAIProjectResourceId)) { + name: take('${name}-ai-project-${projectName}-deployment', 64) + params: { + name: projectName + desc: projectDescription + aiServicesName: cognitiveService.name + location: location + tags: tags + azureExistingAIProjectResourceId: azureExistingAIProjectResourceId + } +} + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + +@description('The private endpoints of the congitive services account.') +output privateEndpoints privateEndpointOutputType[] = [ + for (pe, index) in (privateEndpoints ?? []): { + name: cognitiveService_privateEndpoints[index].outputs.name + resourceId: cognitiveService_privateEndpoints[index].outputs.resourceId + groupId: cognitiveService_privateEndpoints[index].outputs.?groupId! + customDnsConfigs: cognitiveService_privateEndpoints[index].outputs.customDnsConfigs + networkInterfaceResourceIds: cognitiveService_privateEndpoints[index].outputs.networkInterfaceResourceIds + } +] + +import { aiProjectOutputType } from 'project.bicep' +output aiProjectInfo aiProjectOutputType = aiProject.outputs.aiProjectInfo + +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for the private endpoint output.') +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The type for a cognitive services account deployment.') +type deploymentType = { + @description('Optional. Specify the name of cognitive service account deployment.') + name: string? + + @description('Required. Properties of Cognitive Services account deployment model.') + model: { + @description('Required. The name of Cognitive Services account deployment model.') + name: string + + @description('Required. The format of Cognitive Services account deployment model.') + format: string + + @description('Required. The version of Cognitive Services account deployment model.') + version: string + } + + @description('Optional. The resource model definition representing SKU.') + sku: { + @description('Required. The name of the resource model definition representing SKU.') + name: string + + @description('Optional. The capacity of the resource model definition representing SKU.') + capacity: int? + + @description('Optional. The tier of the resource model definition representing SKU.') + tier: string? + + @description('Optional. The size of the resource model definition representing SKU.') + size: string? + + @description('Optional. The family of the resource model definition representing SKU.') + family: string? + }? + + @description('Optional. The name of RAI policy.') + raiPolicyName: string? + + @description('Optional. The version upgrade option.') + versionUpgradeOption: string? +} + +@export() +@description('The type for a cognitive services account endpoint.') +type endpointType = { + @description('Type of the endpoint.') + name: string? + @description('The endpoint URI.') + endpoint: string? +} + +@export() +@description('The type of the secrets exported to the provided Key Vault.') +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The name for the accessKey1 secret to create.') + accessKey1Name: string? + + @description('Optional. The name for the accessKey2 secret to create.') + accessKey2Name: string? +} diff --git a/infra/avm/modules/ai/modules/keyVaultExport.bicep b/infra/avm/modules/ai/modules/keyVaultExport.bicep new file mode 100644 index 00000000..ccbcf14b --- /dev/null +++ b/infra/avm/modules/ai/modules/keyVaultExport.bicep @@ -0,0 +1,43 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the secrets in.') +param keyVaultName string + +import { secretToSetType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2026-02-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // + +import { secretSetOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetOutputType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + secretUriWithVersion: secrets[index].properties.secretUriWithVersion + } +] diff --git a/infra/avm/modules/ai/modules/project.bicep b/infra/avm/modules/ai/modules/project.bicep new file mode 100644 index 00000000..3a1620d2 --- /dev/null +++ b/infra/avm/modules/ai/modules/project.bicep @@ -0,0 +1,62 @@ +@description('Required. Name of the AI Services project.') +param name string + +@description('Required. The location of the Project resource.') +param location string = resourceGroup().location + +@description('Optional. The description of the AI Foundry project to create. Defaults to the project name.') +param desc string = name + +@description('Required. Name of the existing Cognitive Services resource to create the AI Foundry project in.') +param aiServicesName string + +@description('Optional. Tags to be applied to the resources.') +param tags object = {} + +@description('Optional. Use this parameter to use an existing AI project resource ID from different resource group') +param azureExistingAIProjectResourceId string = '' + +// // Extract components from existing AI Project Resource ID if provided +var useExistingProject = !empty(azureExistingAIProjectResourceId) +var existingProjName = useExistingProject ? last(split(azureExistingAIProjectResourceId, '/')) : '' +var existingProjEndpoint = useExistingProject ? format('https://{0}.services.ai.azure.com/api/projects/{1}', aiServicesName, existingProjName) : '' + +// Reference to cognitive service in current resource group for new projects +resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesName +} + +// Create new AI project only if not reusing existing one +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = if(!useExistingProject) { + parent: cogServiceReference + name: name + tags: tags + location: location + identity: { + type: 'SystemAssigned' + } + properties: { + description: desc + displayName: name + } +} + +@description('AI Project metadata including name, resource ID, and API endpoint.') +output aiProjectInfo aiProjectOutputType = { + name: useExistingProject ? existingProjName : aiProject.name + resourceId: useExistingProject ? azureExistingAIProjectResourceId : aiProject.id + apiEndpoint: useExistingProject ? existingProjEndpoint : aiProject.properties.endpoints['AI Foundry API'] +} + +@export() +@description('Output type representing AI project information.') +type aiProjectOutputType = { + @description('Required. Name of the AI project.') + name: string + + @description('Required. Resource ID of the AI project.') + resourceId: string + + @description('Required. API endpoint for the AI project.') + apiEndpoint: string +} diff --git a/infra/avm/modules/compute/app-service-plan.bicep b/infra/avm/modules/compute/app-service-plan.bicep new file mode 100644 index 00000000..6e9e72d0 --- /dev/null +++ b/infra/avm/modules/compute/app-service-plan.bicep @@ -0,0 +1,67 @@ +// ============================================================================ +// Module: App Service Plan +// Description: AVM wrapper for Azure App Service Plan +// AVM Module: avm/res/web/serverfarm:0.7.0 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service Plan.') +param name string = 'asp-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the App Service Plan.') +@allowed(['F1', 'D1', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1', 'P2', 'P3', 'P4', 'P0v3', 'P0v4', 'P1v3', 'P1v4', 'P2v3', 'P3v3']) +param skuName string = 'B2' + +@description('Whether the plan is Linux-based.') +param reserved bool = true + +@description('Kind of the App Service Plan.') +param kind string = 'linux' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Number of instances (workers).') +param skuCapacity int = 1 + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Enable zone redundancy. Requires Premium SKU (P1v3+).') +param zoneRedundant bool = false + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module appServicePlan 'br/public:avm/res/web/serverfarm:0.7.0' = { + name: take('avm.res.web.serverfarm.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + skuCapacity: skuCapacity + reserved: reserved + kind: kind + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + zoneRedundant: zoneRedundant + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service Plan.') +output resourceId string = appServicePlan.outputs.resourceId + +@description('Name of the App Service Plan.') +output name string = appServicePlan.outputs.name diff --git a/infra/avm/modules/compute/app-service.bicep b/infra/avm/modules/compute/app-service.bicep new file mode 100644 index 00000000..a41f96f5 --- /dev/null +++ b/infra/avm/modules/compute/app-service.bicep @@ -0,0 +1,115 @@ +// ============================================================================ +// Module: App Service +// Description: AVM wrapper for Azure App Service (Web App) +// AVM Module: avm/res/web/site:0.23.1 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service.') +param name string = solutionName + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Docker image name (e.g., DOCKER|registry.azurecr.io/image:tag).') +param linuxFxVersion string + +@description('Application settings key-value pairs.') +param appSettings object = {} + +@description('Whether to enable Always On.') +param alwaysOn bool = true + +@description('Kind of web app.') +param kind string = 'app,linux' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Subnet resource ID for VNet integration.') +param virtualNetworkSubnetId string = '' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module appService 'br/public:avm/res/web/site:0.23.1' = { + name: take('avm.res.web.site.${name}', 64) + params: { + name: name + location: location + tags: tags + kind: kind + enableTelemetry: enableTelemetry + serverFarmResourceId: serverFarmResourceId + managedIdentities: { + systemAssigned: true + } + siteConfig: { + alwaysOn: alwaysOn + ftpsState: 'Disabled' + linuxFxVersion: linuxFxVersion + minTlsVersion: '1.2' + } + e2eEncryptionEnabled: true + configs: [ + { + name: 'appsettings' + properties: appSettings + } + { + name: 'logs' + properties: { + applicationLogs: { fileSystem: { level: 'Verbose' } } + detailedErrorMessages: { enabled: true } + failedRequestsTracing: { enabled: true } + httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } } + } + } + ] + publicNetworkAccess: publicNetworkAccess + virtualNetworkSubnetResourceId: !empty(virtualNetworkSubnetId) ? virtualNetworkSubnetId : null + basicPublishingCredentialsPolicies: [ + { + name: 'ftp' + allow: false + } + { + name: 'scm' + allow: false + } + ] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service.') +output resourceId string = appService.outputs.resourceId + +@description('Name of the App Service.') +output name string = appService.outputs.name + +@description('Default hostname of the App Service.') +output defaultHostname string = appService.outputs.defaultHostname + +@description('URL of the App Service.') +output appUrl string = 'https://${appService.outputs.defaultHostname}' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = appService.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/compute/container-app-environment.bicep b/infra/avm/modules/compute/container-app-environment.bicep new file mode 100644 index 00000000..1f488eed --- /dev/null +++ b/infra/avm/modules/compute/container-app-environment.bicep @@ -0,0 +1,95 @@ +// ============================================================================ +// Module: Azure Container Apps Environment (AVM) +// AVM Module: avm/res/app/managed-environment:0.13.3 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Container Apps Environment.') +param name string = 'cae-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace (required when enableMonitoring is true).') +param logAnalyticsWorkspaceResourceId string = '' + +@description('Subnet resource ID for VNet integration (required when enablePrivateNetworking is true).') +param infrastructureSubnetId string = '' + +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('Enable private networking (internal environment, public access disabled).') +param enablePrivateNetworking bool = false + +@description('Enable monitoring (Log Analytics + App Insights).') +param enableMonitoring bool = true + +@description('Application Insights connection string (optional, for App Insights integration).') +param appInsightsConnectionString string = '' + +@description('Enable redundancy (dedicated workload profiles + infra resource group).') +param enableRedundancy bool = false + +@description('Infrastructure resource group name (used when zone redundancy is enabled). Defaults to "{resourceGroup}-infra" if empty.') +param infrastructureResourceGroupName string = '${resourceGroup().name}-infra' + +@description('Workload profiles configuration (e.g., Consumption or dedicated D4 profiles).') +param workloadProfiles array = [ + { + name: 'Consumption' + workloadProfileType: 'Consumption' + } +] + +// ============================================================================ +// Container Apps Environment (AVM) +// ============================================================================ +module managedEnvironment 'br/public:avm/res/app/managed-environment:0.13.3' = { + name: take('avm.res.app.managedenvironment.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + // WAF: Private networking + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + internal: enablePrivateNetworking + infrastructureSubnetResourceId: !empty(infrastructureSubnetId) ? infrastructureSubnetId : null + // WAF: Monitoring + appLogsConfiguration: enableMonitoring && !empty(logAnalyticsWorkspaceResourceId) + ? { + destination: 'log-analytics' + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + } + : null + appInsightsConnectionString: !empty(appInsightsConnectionString) ? appInsightsConnectionString : null + // WAF: Redundancy + zoneRedundant: zoneRedundant || enableRedundancy + infrastructureResourceGroupName: !empty(infrastructureResourceGroupName) ? infrastructureResourceGroupName : null + workloadProfiles: workloadProfiles + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the Container Apps Environment.') +output name string = managedEnvironment.outputs.name + +@description('The resource ID of the Container Apps Environment.') +output resourceId string = managedEnvironment.outputs.resourceId + +@description('The default domain of the Container Apps Environment.') +output defaultDomain string = managedEnvironment.outputs.defaultDomain + +@description('The static IP of the Container Apps Environment.') +output staticIp string = managedEnvironment.outputs.staticIp diff --git a/infra/avm/modules/compute/container-app.bicep b/infra/avm/modules/compute/container-app.bicep new file mode 100644 index 00000000..07e7b4f9 --- /dev/null +++ b/infra/avm/modules/compute/container-app.bicep @@ -0,0 +1,105 @@ +// ============================================================================ +// Module: Azure Container App (AVM) +// AVM Module: avm/res/app/container-app:0.22.1 +// ============================================================================ + +@description('Name of the container app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Container Apps Environment.') +param environmentResourceId string + +@description('Container definitions.') +param containers array + +@description('Enable external ingress.') +param ingressExternal bool = true + +@description('Target port for ingress.') +param ingressTargetPort int = 80 + +@description('Ingress transport protocol.') +@allowed(['auto', 'http', 'http2', 'tcp']) +param ingressTransport string = 'auto' + +@description('Whether to allow insecure ingress connections.') +param ingressAllowInsecure bool = false + +@description('Disable ingress entirely (for background workers).') +param disableIngress bool = false + +@description('Container registry configurations.') +param registries array? + +@description('Secret definitions.') +param secrets array? + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('CORS policy configuration.') +param corsPolicy object = {} + +@description('Active revision mode.') +@allowed(['Single', 'Multiple']) +param activeRevisionsMode string = 'Single' + +@description('Scale settings (maxReplicas, minReplicas, rules, cooldownPeriod, pollingInterval).') +param scaleSettings object = { + maxReplicas: 10 + minReplicas: 0 +} + +@description('Workload profile name.') +param workloadProfileName string? + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Container App (AVM) +// ============================================================================ +module containerApp 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.containerapp.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + environmentResourceId: environmentResourceId + containers: containers + ingressExternal: disableIngress ? false : ingressExternal + ingressTargetPort: ingressTargetPort + ingressTransport: ingressTransport + ingressAllowInsecure: ingressAllowInsecure + disableIngress: disableIngress + registries: registries + secrets: secrets + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + corsPolicy: !empty(corsPolicy) ? corsPolicy : null + activeRevisionsMode: activeRevisionsMode + scaleSettings: scaleSettings + workloadProfileName: workloadProfileName + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container app.') +output name string = containerApp.outputs.name + +@description('The resource ID of the container app.') +output resourceId string = containerApp.outputs.resourceId + +@description('The FQDN of the container app.') +output fqdn string = containerApp.outputs.fqdn + +@description('System-assigned identity principal ID.') +output principalId string = containerApp.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/compute/container-instance.bicep b/infra/avm/modules/compute/container-instance.bicep new file mode 100644 index 00000000..c840be20 --- /dev/null +++ b/infra/avm/modules/compute/container-instance.bicep @@ -0,0 +1,120 @@ +// ============================================================================ +// Module: Azure Container Instance (AVM) +// AVM Module: avm/res/container-instance/container-group:0.7.0 +// ============================================================================ + +@description('Name of the container group.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Container image to deploy.') +param containerImage string + +@description('CPU cores for the container.') +param cpu int = 2 + +@description('Memory in GB for the container.') +param memoryInGB int = 4 + +@description('Port to expose.') +param port int = 8000 + +@description('Environment variables for the container.') +param environmentVariables array = [] + +@description('Operating system type.') +@allowed(['Linux', 'Windows']) +param osType string = 'Linux' + +@description('Restart policy.') +@allowed(['Always', 'OnFailure', 'Never']) +param restartPolicy string = 'Always' + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Image registry credentials.') +param imageRegistryCredentials array = [] + +@description('Subnet resource ID for VNet integration. If empty, public IP is used.') +param subnetResourceId string = '' + +@description('Availability zone for the container group. Use -1 for no zone.') +param availabilityZone int = -1 + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Variables +// ============================================================================ +var isPrivateNetworking = !empty(subnetResourceId) + +var containers = [ + { + name: name + properties: { + image: containerImage + resources: { + requests: { + cpu: cpu + memoryInGB: string(memoryInGB) + } + } + ports: [ + { + port: port + protocol: 'TCP' + } + ] + environmentVariables: environmentVariables + } + } +] + +// ============================================================================ +// Container Instance (AVM) +// ============================================================================ +module containerGroup 'br/public:avm/res/container-instance/container-group:0.7.0' = { + name: take('avm.res.containerinstance.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + containers: containers + osType: osType + restartPolicy: restartPolicy + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + ipAddress: { + type: isPrivateNetworking ? 'Private' : 'Public' + ports: [ + { + port: port + protocol: 'TCP' + } + ] + dnsNameLabel: isPrivateNetworking ? null : name + } + imageRegistryCredentials: !empty(imageRegistryCredentials) ? imageRegistryCredentials : [] + subnets: isPrivateNetworking ? [{ subnetResourceId: subnetResourceId }] : [] + availabilityZone: availabilityZone + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container group.') +output name string = containerGroup.outputs.name + +@description('The resource ID of the container group.') +output resourceId string = containerGroup.outputs.resourceId + +@description('The IP address of the container group.') +output ipAddress string = containerGroup.outputs.?iPv4Address ?? '' diff --git a/infra/avm/modules/compute/container-registry.bicep b/infra/avm/modules/compute/container-registry.bicep new file mode 100644 index 00000000..b3e0180f --- /dev/null +++ b/infra/avm/modules/compute/container-registry.bicep @@ -0,0 +1,104 @@ +// ============================================================================ +// Module: Azure Container Registry (AVM) +// AVM Module: avm/res/container-registry/registry:0.12.1 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the container registry.') +param name string = replace('cr${solutionName}', '-', '') + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the container registry.') +@allowed(['Basic', 'Standard', 'Premium']) +param sku string = 'Premium' + +@description('Enable admin user for the registry.') +param adminUserEnabled bool = false + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Export policy status. Must be "enabled" when publicNetworkAccess is "Enabled".') +param exportPolicyStatus string = 'enabled' + +@description('Principal IDs to assign AcrPull role.') +param acrPullPrincipalIds array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for private endpoint.') +param privateDnsZoneResourceIds array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Role Assignments +// ============================================================================ +var acrPullRoleId = '7f951dda-4ed3-4680-a7ca-43fe172d538d' + +var roleAssignments = [for principalId in acrPullPrincipalIds: { + principalId: principalId + roleDefinitionIdOrName: acrPullRoleId + principalType: 'ServicePrincipal' +}] + +// ============================================================================ +// Private Endpoint Config +// ============================================================================ +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +// ============================================================================ +// Container Registry (AVM) +// ============================================================================ +module containerRegistry 'br/public:avm/res/container-registry/registry:0.12.1' = { + name: take('avm.res.containerregistry.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + acrSku: sku + acrAdminUserEnabled: adminUserEnabled + publicNetworkAccess: publicNetworkAccess + exportPolicyStatus: exportPolicyStatus + roleAssignments: !empty(acrPullPrincipalIds) ? roleAssignments : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container registry.') +output name string = containerRegistry.outputs.name + +@description('The login server URL.') +output loginServer string = containerRegistry.outputs.loginServer + +@description('The resource ID of the container registry.') +output resourceId string = containerRegistry.outputs.resourceId diff --git a/infra/avm/modules/compute/function-app.bicep b/infra/avm/modules/compute/function-app.bicep new file mode 100644 index 00000000..f6d84945 --- /dev/null +++ b/infra/avm/modules/compute/function-app.bicep @@ -0,0 +1,95 @@ +// ============================================================================ +// Module: Azure Function App (AVM) +// AVM Module: avm/res/web/site:0.23.1 +// ============================================================================ + +@description('Name of the function app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Resource ID of the storage account for function app.') +param storageAccountResourceId string + +@description('Name of the storage account.') +param storageAccountName string + +@description('Managed identity configuration.') +param managedIdentities object = { + systemAssigned: true +} + +@description('App settings as name-value pairs.') +param appSettings array = [] + +@description('Site configuration object.') +param siteConfig object = {} + +@description('Runtime stack.') +param runtimeStack string = 'python' + +@description('Runtime version.') +param runtimeVersion string = '3.11' + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Variables +// ============================================================================ +var baseAppSettings = { + AzureWebJobsStorage__accountName: storageAccountName + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: runtimeStack +} + +var customAppSettings = reduce(appSettings, {}, (cur, next) => union(cur, { '${next.name}': next.value })) +var mergedAppSettings = union(baseAppSettings, customAppSettings) + +// ============================================================================ +// Function App (AVM) +// ============================================================================ +module functionApp 'br/public:avm/res/web/site:0.23.1' = { + name: take('avm.res.web.site.func.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + kind: 'functionapp,linux' + serverFarmResourceId: serverFarmResourceId + storageAccountRequired: false + managedIdentities: managedIdentities + configs: [ + { + name: 'appsettings' + properties: mergedAppSettings + } + ] + siteConfig: union({ + linuxFxVersion: '${toUpper(runtimeStack)}|${runtimeVersion}' + }, siteConfig) + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the function app.') +output name string = functionApp.outputs.name + +@description('The resource ID of the function app.') +output resourceId string = functionApp.outputs.resourceId + +@description('The default hostname of the function app.') +output defaultHostName string = functionApp.outputs.defaultHostname + +@description('The principal ID of the system-assigned managed identity.') +output principalId string = functionApp.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/compute/kubernetes.bicep b/infra/avm/modules/compute/kubernetes.bicep new file mode 100644 index 00000000..54053dd4 --- /dev/null +++ b/infra/avm/modules/compute/kubernetes.bicep @@ -0,0 +1,158 @@ +// ============================================================================ +// Module: Azure Kubernetes Service (AKS) +// Description: AVM wrapper for Azure Kubernetes Service Managed Cluster +// AVM Module: avm/res/container-service/managed-cluster:0.13.1 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the AKS cluster.') +param name string = 'aks-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Kubernetes version for the cluster.') +param kubernetesVersion string = '1.34' + +@description('Agent pool configurations. Each entry requires name, vmSize, count, mode (System/User).') +param agentPools array = [ + { + name: 'agentpool' + vmSize: 'Standard_D4ds_v5' + count: 2 + minCount: 1 + maxCount: 2 + enableAutoScaling: true + osType: 'Linux' + mode: 'System' + type: 'VirtualMachineScaleSets' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + } +] + +@description('Enable Kubernetes RBAC.') +param enableRBAC bool = true + +@description('Disable local accounts (enforce AAD-only).') +param disableLocalAccounts bool = false + +@description('Network plugin for the cluster.') +@allowed(['azure', 'kubenet', 'none']) +param networkPlugin string = 'azure' + +@description('Network policy for the cluster.') +@allowed(['azure', 'calico', '']) +param networkPolicy string = 'azure' + +@description('DNS prefix for the cluster.') +param dnsPrefix string = '' + +@description('SKU tier for the cluster.') +@allowed(['Free', 'Standard', 'Premium']) +param skuTier string = 'Standard' + +@description('Service CIDR for Kubernetes services.') +param serviceCidr string = '10.20.0.0/16' + +@description('DNS service IP (must be within serviceCidr).') +param dnsServiceIP string = '10.20.0.10' + +@description('Auto-upgrade channel for the cluster.') +@allowed(['none', 'patch', 'rapid', 'stable', 'node-image']) +param autoUpgradeChannel string = 'stable' + +@description('Log Analytics workspace resource ID for monitoring.') +param logAnalyticsWorkspaceResourceId string = '' + +// --- WAF: Networking --- +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Enable private cluster (API server not publicly accessible).') +param enablePrivateCluster bool = false + +@description('Subnet resource ID for the agent pool (for VNet integration).') +param agentPoolSubnetId string = '' + +@description('Enable Microsoft Defender for Containers.') +param enableDefender bool = false + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Role assignments for the cluster.') +param roleAssignments array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Variables +// ============================================================================ +var effectiveDnsPrefix = !empty(dnsPrefix) ? dnsPrefix : name +var enableMonitoring = !empty(logAnalyticsWorkspaceResourceId) + +var effectiveAgentPools = [for pool in agentPools: union(pool, !empty(agentPoolSubnetId) ? { vnetSubnetResourceId: agentPoolSubnetId } : {})] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module aksCluster 'br/public:avm/res/container-service/managed-cluster:0.13.1' = { + name: take('avm.res.container-service.managed-cluster.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + kubernetesVersion: kubernetesVersion + primaryAgentPoolProfiles: effectiveAgentPools + enableRBAC: enableRBAC + disableLocalAccounts: disableLocalAccounts + networkPlugin: networkPlugin + networkPolicy: networkPolicy + dnsPrefix: effectiveDnsPrefix + skuTier: skuTier + serviceCidr: serviceCidr + dnsServiceIP: dnsServiceIP + publicNetworkAccess: publicNetworkAccess + apiServerAccessProfile: { + enablePrivateCluster: enablePrivateCluster + } + autoUpgradeProfile: { + upgradeChannel: autoUpgradeChannel + nodeOSUpgradeChannel: 'Unmanaged' + } + managedIdentities: { systemAssigned: true } + omsAgentEnabled: enableMonitoring + monitoringWorkspaceResourceId: enableMonitoring ? logAnalyticsWorkspaceResourceId : null + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + securityProfile: enableDefender && enableMonitoring ? { + defender: { + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + securityMonitoring: { + enabled: true + } + } + } : {} + roleAssignments: roleAssignments + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AKS cluster.') +output name string = aksCluster.outputs.name + +@description('Resource ID of the AKS cluster.') +output resourceId string = aksCluster.outputs.resourceId + +@description('FQDN of the AKS cluster.') +output fqdn string = aksCluster.outputs.?fqdn ?? '' diff --git a/infra/avm/modules/compute/maintenance-configuration.bicep b/infra/avm/modules/compute/maintenance-configuration.bicep new file mode 100644 index 00000000..2683939d --- /dev/null +++ b/infra/avm/modules/compute/maintenance-configuration.bicep @@ -0,0 +1,84 @@ +// ============================================================================ +// Module: Maintenance Configuration +// Description: AVM wrapper for Azure Maintenance Configuration +// AVM Module: avm/res/maintenance/maintenance-configuration +// WAF: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the maintenance configuration.') +param name string = 'mc-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Maintenance scope.') +param maintenanceScope string = 'InGuestPatch' + +@description('Visibility of the configuration.') +param visibility string = 'Custom' + +@description('Extension properties.') +param extensionProperties object = { + InGuestPatchMode: 'User' +} + +@description('Maintenance window configuration.') +param maintenanceWindow object = { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' +} + +@description('Install patches configuration.') +param installPatches object = { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } +} + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = { + name: take('avm.res.maintenance.maintenance-configuration.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + extensionProperties: extensionProperties + maintenanceScope: maintenanceScope + maintenanceWindow: maintenanceWindow + visibility: visibility + installPatches: installPatches + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the maintenance configuration.') +output resourceId string = maintenanceConfiguration.outputs.resourceId + +@description('Name of the maintenance configuration.') +output name string = maintenanceConfiguration.outputs.name diff --git a/infra/avm/modules/compute/proximity-placement-group.bicep b/infra/avm/modules/compute/proximity-placement-group.bicep new file mode 100644 index 00000000..f1a3e279 --- /dev/null +++ b/infra/avm/modules/compute/proximity-placement-group.bicep @@ -0,0 +1,51 @@ +// ============================================================================ +// Module: Proximity Placement Group +// Description: AVM wrapper for Azure Proximity Placement Group +// AVM Module: avm/res/compute/proximity-placement-group +// WAF: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the proximity placement group.') +param name string = 'ppg-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Availability zone for the proximity placement group.') +param availabilityZone int = 1 + +@description('VM sizes intent for the proximity placement group.') +param vmSizes array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-group:0.4.1' = { + name: take('avm.res.compute.proximity-placement-group.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + availabilityZone: availabilityZone + intent: !empty(vmSizes) ? { vmSizes: vmSizes } : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the proximity placement group.') +output resourceId string = proximityPlacementGroup.outputs.resourceId + +@description('Name of the proximity placement group.') +output name string = proximityPlacementGroup.outputs.name diff --git a/infra/avm/modules/compute/virtual-machine.bicep b/infra/avm/modules/compute/virtual-machine.bicep new file mode 100644 index 00000000..8b9c2a7e --- /dev/null +++ b/infra/avm/modules/compute/virtual-machine.bicep @@ -0,0 +1,157 @@ +// ============================================================================ +// Module: Virtual Machine (Jumpbox) +// Description: AVM wrapper for Azure Virtual Machine with Entra ID authentication +// AVM Module: avm/res/compute/virtual-machine +// Ref: https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the virtual machine.') +param name string = 'vm-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('VM size.') +param vmSize string = 'Standard_D2s_v5' + +@secure() +@description('Local admin username. Required by Azure at provisioning time but not used for login when Entra ID is enabled.') +param adminUsername string + +@secure() +@description('Local admin password. Required by Azure at provisioning time but not used for login when Entra ID is enabled.') +param adminPassword string + +@description('Resource ID of the subnet for the VM NIC.') +param subnetResourceId string + +@description('OS type for the VM.') +param osType string = 'Windows' + +@description('Availability zone for the VM.') +param availabilityZone int = 1 + +@description('Image reference for the VM.') +param imageReference object = { + publisher: 'microsoft-dsvm' + offer: 'dsvm-win-2022' + sku: 'winserver-2022' + version: 'latest' +} + +@description('OS disk size in GB.') +param osDiskSizeGB int = 128 + +@description('Resource ID of the maintenance configuration.') +param maintenanceConfigurationResourceId string? + +@description('Resource ID of the proximity placement group.') +param proximityPlacementGroupResourceId string? + +@description('Monitoring agent extension configuration (data collection rule associations).') +param extensionMonitoringAgentConfig object? + +@description('Diagnostic settings for the resource.') +param diagnosticSettings array? + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('Deploying user principal ID. Used for default role assignment to grant the deploying user login access to the VM. This is required because with Entra ID authentication enabled, local accounts cannot be used to access the VM, including the local admin account created at provisioning.') +param deployingUserPrincipalId string + +@description('Deploying user principal type. Used for default role assignment to grant the deploying user login access to the VM. This is required because with Entra ID authentication enabled, local accounts cannot be used to access the VM, including the local admin account created at provisioning.') +param deployingUserPrincipalType string = 'User' + +@description('Role assignments to apply to the virtual machine.') +param roleAssignments array = [ + { + roleDefinitionIdOrName: '1c0163c0-47e6-4577-8991-ea5c82e286e4' // Virtual Machine Administrator Login + principalId: deployingUserPrincipalId + principalType: deployingUserPrincipalType + } +] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.22.0' = { + name: take('avm.res.compute.virtual-machine.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + computerName: take(name, 15) + osType: osType + vmSize: vmSize + adminUsername: adminUsername + adminPassword: adminPassword + managedIdentities: { systemAssigned: true } + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: maintenanceConfigurationResourceId + enableAutomaticUpdates: true + encryptionAtHost: true + availabilityZone: availabilityZone + proximityPlacementGroupResourceId: proximityPlacementGroupResourceId + imageReference: imageReference + osDisk: { + name: 'osdisk-${name}' + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: osDiskSizeGB + managedDisk: { storageAccountType: 'Premium_LRS' } + } + nicConfigurations: [ + { + name: 'nic-${name}' + tags: tags + deleteOption: 'Delete' + diagnosticSettings: diagnosticSettings + ipConfigurations: [ + { + name: '${name}-nic01-ipconfig01' + subnetResourceId: subnetResourceId + diagnosticSettings: diagnosticSettings + } + ] + } + ] + roleAssignments: roleAssignments + extensionAadJoinConfig: { + enabled: true + tags: tags + typeHandlerVersion: '2.0' + settings: { mdmId: '' } + } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { day: '7', isEnabled: 'true', scanType: 'Quick', time: '120' } + } + tags: tags + } + extensionMonitoringAgentConfig: extensionMonitoringAgentConfig + extensionNetworkWatcherAgentConfig: { enabled: true, tags: tags } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the virtual machine.') +output resourceId string = virtualMachine.outputs.resourceId + +@description('Name of the virtual machine.') +output name string = virtualMachine.outputs.name diff --git a/infra/avm/modules/data/app-configuration.bicep b/infra/avm/modules/data/app-configuration.bicep new file mode 100644 index 00000000..ee3fb318 --- /dev/null +++ b/infra/avm/modules/data/app-configuration.bicep @@ -0,0 +1,98 @@ +// ============================================================================ +// Module: Azure App Configuration (AVM) +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the App Configuration store.') +param name string = 'appcs-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('SKU for the configuration store.') +@allowed(['Free', 'Standard']) +param sku string = 'Standard' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Enable purge protection.') +param enablePurgeProtection bool = false + +@description('Soft delete retention in days.') +param softDeleteRetentionInDays int = 7 + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Role assignments.') +param roleAssignments array = [] + +@description('Key-value pairs to store in the configuration.') +param keyValues array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +// ============================================================================ +// App Configuration (AVM) +// ============================================================================ + +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +module configStore 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { + name: take('avm.res.appconfiguration.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: sku + disableLocalAuth: disableLocalAuth + enablePurgeProtection: enablePurgeProtection + softDeleteRetentionInDays: softDeleteRetentionInDays + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + keyValues: !empty(keyValues) ? keyValues : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the configuration store.') +output name string = configStore.outputs.name + +@description('The endpoint of the configuration store.') +output endpoint string = configStore.outputs.endpoint + +@description('The resource ID of the configuration store.') +output resourceId string = configStore.outputs.resourceId diff --git a/infra/avm/modules/data/cosmos-db-mongo.bicep b/infra/avm/modules/data/cosmos-db-mongo.bicep new file mode 100644 index 00000000..36baef6c --- /dev/null +++ b/infra/avm/modules/data/cosmos-db-mongo.bicep @@ -0,0 +1,137 @@ +// ============================================================================ +// Module: Cosmos DB (MongoDB) +// Description: AVM wrapper for Azure Cosmos DB with MongoDB API +// AVM Module: avm/res/document-db/database-account:0.19.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/cosmos-db +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('MongoDB database name.') +param databaseName string = 'default' + +@description('MongoDB collections to create.') +param collections array = [] + +@description('MongoDB server version.') +@allowed(['4.2', '5.0', '6.0', '7.0']) +param serverVersion string = '7.0' + +@description('Enable analytical storage (Synapse Link).') +param enableAnalyticalStorage bool = false + +@description('Default consistency level.') +@allowed(['Eventual', 'ConsistentPrefix', 'Session', 'BoundedStaleness', 'Strong']) +param consistencyLevel string = 'Session' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for Cosmos DB (MongoDB).') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- WAF: Redundancy --- +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable automatic failover.') +param enableAutomaticFailover bool = false + +@description('Optional. HA paired region for multi-region failover when redundancy is enabled.') +param haLocation string = '' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module cosmosAccount 'br/public:avm/res/document-db/database-account:0.19.0' = { + name: take('avm.res.document-db.database-account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + capabilitiesToAdd: ['EnableMongo'] + serverVersion: serverVersion + enableAnalyticalStorage: enableAnalyticalStorage + defaultConsistencyLevel: consistencyLevel + mongodbDatabases: [ + { + name: databaseName + collections: collections + } + ] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + networkRestrictions: { + networkAclBypass: 'None' + publicNetworkAccess: publicNetworkAccess + } + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'MongoDB' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + zoneRedundant: zoneRedundant + enableAutomaticFailover: enableAutomaticFailover + failoverLocations: zoneRedundant && !empty(haLocation) + ? [ + { failoverPriority: 0, isZoneRedundant: true, locationName: location } + { failoverPriority: 1, isZoneRedundant: true, locationName: haLocation } + ] + : [ + { locationName: location, failoverPriority: 0, isZoneRedundant: false } + ] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmosAccount.outputs.resourceId + +@description('Name of the Cosmos DB account.') +output name string = cosmosAccount.outputs.name + +@description('MongoDB connection string (without credentials — use Key Vault for secrets).') +output connectionString string = 'mongodb+srv://${name}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000' + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.mongo.cosmos.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName diff --git a/infra/avm/modules/data/cosmos-db-nosql.bicep b/infra/avm/modules/data/cosmos-db-nosql.bicep new file mode 100644 index 00000000..49c39f76 --- /dev/null +++ b/infra/avm/modules/data/cosmos-db-nosql.bicep @@ -0,0 +1,146 @@ +// ============================================================================ +// Module: Cosmos DB +// Description: AVM wrapper for Azure Cosmos DB (NoSQL) with WAF alignment +// AVM Module: avm/res/document-db/database-account:0.19.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/cosmos-db +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Database name.') +param databaseName string = 'db_conversation_history' + +@description('Container definitions.') +param containers array = [ + { + name: 'conversations' + partitionKeyPath: '/userId' + } +] + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for Cosmos DB.') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- WAF: Redundancy --- +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable automatic failover.') +param enableAutomaticFailover bool = false + +@description('Optional. HA paired region for multi-region failover when redundancy is enabled.') +param haLocation string = '' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module cosmosAccount 'br/public:avm/res/document-db/database-account:0.19.0' = { + name: take('avm.res.document-db.database-account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + capabilitiesToAdd: zoneRedundant ? [] : ['EnableServerless'] + sqlDatabases: [ + { + name: databaseName + containers: [for container in containers: { + name: container.name + paths: [container.partitionKeyPath] + kind: 'Hash' + version: 2 + }] + } + ] + sqlRoleAssignments: [] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + networkRestrictions: { + networkAclBypass: 'None' + publicNetworkAccess: publicNetworkAccess + } + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'Sql' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + zoneRedundant: zoneRedundant + enableAutomaticFailover: enableAutomaticFailover + failoverLocations: zoneRedundant + ? [ + { + failoverPriority: 0 + isZoneRedundant: true + locationName: location + } + { + failoverPriority: 1 + isZoneRedundant: true + locationName: haLocation + } + ] + : [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmosAccount.outputs.resourceId + +@description('Name of the Cosmos DB account.') +output name string = cosmosAccount.outputs.name + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.documents.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName + +@description('Container name (first container).') +output containerName string = containers[0].name diff --git a/infra/avm/modules/data/event-grid.bicep b/infra/avm/modules/data/event-grid.bicep new file mode 100644 index 00000000..16c67516 --- /dev/null +++ b/infra/avm/modules/data/event-grid.bicep @@ -0,0 +1,65 @@ +// ============================================================================ +// Module: Azure Event Grid System Topic +// Description: AVM wrapper for Azure Event Grid System Topic +// AVM Module: avm/res/event-grid/system-topic:0.6.5 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Event Grid System Topic.') +param name string = 'evgt-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Resource ID of the source that publishes events (e.g., Storage Account resource ID).') +param source string + +@description('The type of the event source. E.g., Microsoft.Storage.StorageAccounts.') +param topicType string + +@description('Event subscriptions to create on the system topic.') +param eventSubscriptions array = [] + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Managed identities configuration.') +param managedIdentities object = {} + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module eventGridSystemTopic 'br/public:avm/res/event-grid/system-topic:0.6.5' = { + name: take('avm.res.event-grid.system-topic.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + source: source + topicType: topicType + eventSubscriptions: eventSubscriptions + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + managedIdentities: !empty(managedIdentities) ? managedIdentities : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the Event Grid System Topic.') +output name string = eventGridSystemTopic.outputs.name + +@description('Resource ID of the Event Grid System Topic.') +output resourceId string = eventGridSystemTopic.outputs.resourceId + +@description('System-assigned principal ID (if enabled).') +output systemAssignedMIPrincipalId string = eventGridSystemTopic.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/data/event-hub.bicep b/infra/avm/modules/data/event-hub.bicep new file mode 100644 index 00000000..3e8efd60 --- /dev/null +++ b/infra/avm/modules/data/event-hub.bicep @@ -0,0 +1,92 @@ +// ============================================================================ +// Module: Azure Event Hub Namespace (AVM) +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Event Hub namespace.') +param name string = 'evhns-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('SKU configuration for the namespace.') +param sku object = { + name: 'Standard' + capacity: 1 +} + +@description('Event hubs to create within the namespace.') +param eventhubs array = [] + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Role assignments.') +param roleAssignments array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +// ============================================================================ +// Event Hub Namespace (AVM) +// ============================================================================ + +var eventHubItems = [for eh in eventhubs: { + name: eh.name + messageRetentionInDays: contains(eh, 'messageRetentionInDays') ? eh.messageRetentionInDays : 1 + partitionCount: contains(eh, 'partitionCount') ? eh.partitionCount : 2 +}] + +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +module eventHubNamespace 'br/public:avm/res/event-hub/namespace:0.14.1' = { + name: take('avm.res.eventhub.namespace.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: sku.name + skuCapacity: sku.capacity + eventhubs: eventHubItems + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the Event Hub namespace.') +output name string = eventHubNamespace.outputs.name + +@description('The resource ID of the Event Hub namespace.') +output resourceId string = eventHubNamespace.outputs.resourceId diff --git a/infra/avm/modules/data/postgresql-flexible-server.bicep b/infra/avm/modules/data/postgresql-flexible-server.bicep new file mode 100644 index 00000000..42cbc4f4 --- /dev/null +++ b/infra/avm/modules/data/postgresql-flexible-server.bicep @@ -0,0 +1,148 @@ +// ============================================================================ +// Module: PostgreSQL Flexible Server +// Description: AVM wrapper for Azure Database for PostgreSQL Flexible Server +// AVM Module: avm/res/db-for-postgre-sql/flexible-server:0.15.4 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/postgresql +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the PostgreSQL Flexible Server.') +param name string = 'psql-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Azure AD administrators for the server. Each entry requires objectId, principalName, and principalType (User, Group, or ServicePrincipal).') +param administrators array + +@description('The PostgreSQL version to deploy.') +param version string = '16' + +@description('SKU name for the PostgreSQL Flexible Server.') +param skuName string = 'Standard_B1ms' + +@description('SKU tier for the PostgreSQL Flexible Server.') +@allowed(['Burstable', 'GeneralPurpose', 'MemoryOptimized']) +param skuTier string = 'Burstable' + +@description('Storage size in GB.') +param storageSizeGB int = 32 + +@description('Availability zone for the server.') +param availabilityZone int = 1 + +@description('Optional databases to create on the server. Each entry should have a name, and optionally charset and collation.') +param databases array = [] + +@description('Optional server configurations (e.g., extensions). Each entry should have a name, value, and source.') +param configurations array = [] + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for PostgreSQL.') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- WAF: Redundancy --- +@description('High availability mode.') +@allowed(['Disabled', 'SameZone', 'ZoneRedundant']) +param highAvailability string = 'Disabled' + +@description('Standby availability zone for high availability.') +param highAvailabilityZone int = -1 + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module postgresServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:0.15.4' = { + name: take('avm.res.postgre-sql.flexible-server.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + tier: skuTier + storageSizeGB: storageSizeGB + version: version + availabilityZone: availabilityZone + highAvailability: highAvailability + highAvailabilityZone: highAvailabilityZone + publicNetworkAccess: publicNetworkAccess + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + administrators: [for admin in administrators: { + objectId: admin.objectId + principalName: admin.principalName + principalType: admin.principalType + }] + firewallRules: publicNetworkAccess == 'Enabled' ? [ + { + name: 'AllowAllAzureServicesAndResourcesWithinAzureIps' + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + { + name: 'AllowAll' + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } + ] : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'postgresqlServer' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + databases: [for db in databases: { + name: db.name + charset: db.?charset ?? 'UTF8' + collation: db.?collation ?? 'en_US.utf8' + }] + configurations: [for config in configurations: { + name: config.name + value: config.value + source: config.source + }] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Fully qualified domain name of the PostgreSQL Flexible Server.') +output serverFqdn string = postgresServer.outputs.?fqdn ?? '${name}.postgres.database.azure.com' + +@description('Name of the PostgreSQL Flexible Server.') +output name string = postgresServer.outputs.name + +@description('Resource ID of the PostgreSQL Flexible Server.') +output resourceId string = postgresServer.outputs.resourceId diff --git a/infra/avm/modules/data/sql-database.bicep b/infra/avm/modules/data/sql-database.bicep new file mode 100644 index 00000000..4afa61b0 --- /dev/null +++ b/infra/avm/modules/data/sql-database.bicep @@ -0,0 +1,140 @@ +// ============================================================================ +// Module: SQL Database +// Description: AVM wrapper for Azure SQL Server and Database +// AVM Module: avm/res/sql/server:0.21.1 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-sql-database +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the SQL Server.') +param name string = 'sql-${solutionName}' + +@description('Name of the SQL Database.') +param databaseName string = 'sqldb-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Principal ID of the deployer for admin access.') +param deployerPrincipalId string + +@description('SKU name for the database.') +param skuName string = 'GP_S_Gen5' + +@description('SKU tier for the database.') +param skuTier string = 'GeneralPurpose' + +@description('SKU family.') +param skuFamily string = 'Gen5' + +@description('vCore capacity.') +param skuCapacity int = 2 + +@description('Auto-pause delay in minutes.') +param autoPauseDelay int = 60 + +@description('Minimum capacity (vCores).') +param minCapacity int = 1 + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for SQL Server.') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module sqlServer 'br/public:avm/res/sql/server:0.21.1' = { + name: take('avm.res.sql.server.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + minimalTlsVersion: '1.2' + publicNetworkAccess: publicNetworkAccess + restrictOutboundNetworkAccess: 'Disabled' + administrators: { + azureADOnlyAuthentication: true + login: deployerPrincipalId + principalType: 'User' + sid: deployerPrincipalId + tenantId: subscription().tenantId + } + databases: [ + { + name: databaseName + availabilityZone: -1 + collation: 'SQL_Latin1_General_CP1_CI_AS' + autoPauseDelay: autoPauseDelay + minCapacity: '${minCapacity}' + zoneRedundant: false + sku: { + name: skuName + tier: skuTier + family: skuFamily + capacity: skuCapacity + } + } + ] + firewallRules: publicNetworkAccess == 'Enabled' ? [ + { + name: 'AllowSpecificRange' + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } + { + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + ] : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'sqlServer' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Fully qualified domain name of the SQL Server.') +output serverFqdn string = '${name}.database.windows.net' + +@description('Name of the SQL Database.') +output databaseName string = databaseName + +@description('Resource ID of the SQL Server.') +output serverResourceId string = sqlServer.outputs.resourceId + +@description('Name of the SQL Server.') +output name string = sqlServer.outputs.name diff --git a/infra/avm/modules/data/storage-account.bicep b/infra/avm/modules/data/storage-account.bicep new file mode 100644 index 00000000..1ff0e497 --- /dev/null +++ b/infra/avm/modules/data/storage-account.bicep @@ -0,0 +1,135 @@ +// ============================================================================ +// Module: Storage Account +// Description: AVM wrapper for Azure Storage Account with WAF alignment +// AVM Module: avm/res/storage/storage-account:0.32.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/storage-accounts +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the storage account.') +param name string = take('st${toLower(replace(solutionName, '-', ''))}', 24) + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Storage account SKU.') +param skuName string = 'Standard_LRS' + +@description('Storage account kind.') +param kind string = 'StorageV2' + +@description('Access tier.') +@allowed(['Hot', 'Cool']) +param accessTier string = 'Hot' + +@description('Allow blob public access.') +param allowBlobPublicAccess bool = false + +@description('Allow shared key access.') +param allowSharedKeyAccess bool = true + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Blob containers to create.') +param containers array = [ + { + name: 'default' + publicAccess: 'None' + } +] + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Network ACLs for the storage account.') +param networkAcls object = { + defaultAction: 'Allow' + bypass: 'AzureServices' +} + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for Storage (blob).') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- Role Assignments --- +@description('Optional. Array of role assignments to create on the Storage Account.') +param roleAssignments array = [] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module storage 'br/public:avm/res/storage/storage-account:0.32.0' = { + name: take('avm.res.storage.storage-account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + kind: kind + accessTier: accessTier + allowBlobPublicAccess: allowBlobPublicAccess + allowSharedKeyAccess: allowSharedKeyAccess + minimumTlsVersion: 'TLS1_2' + supportsHttpsTrafficOnly: true + requireInfrastructureEncryption: true + publicNetworkAccess: publicNetworkAccess + networkAcls: networkAcls + blobServices: { + containers: [for container in containers: { + name: container.name + publicAccess: container.publicAccess + }] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + } + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'blob' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Storage Account.') +output resourceId string = storage.outputs.resourceId + +@description('Name of the Storage Account.') +output name string = storage.outputs.name + +@description('Primary blob endpoint.') +output blobEndpoint string = storage.outputs.primaryBlobEndpoint + +@description('Service endpoints.') +output serviceEndpoints object = storage.outputs.serviceEndpoints diff --git a/infra/avm/modules/fabric/fabric-capacity.bicep b/infra/avm/modules/fabric/fabric-capacity.bicep new file mode 100644 index 00000000..664f60e0 --- /dev/null +++ b/infra/avm/modules/fabric/fabric-capacity.bicep @@ -0,0 +1,72 @@ +// ============================================================================ +// Module: Fabric Capacity +// Description: AVM wrapper for Microsoft Fabric Capacity +// AVM Module: avm/res/fabric/capacity:0.1.2 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.fabric/capacities +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Fabric capacity. Defaults to fc{solutionName}.') +param name string = 'fc${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU tier of the Fabric capacity.') +@allowed([ + 'F2' + 'F4' + 'F8' + 'F16' + 'F32' + 'F64' + 'F128' + 'F256' + 'F512' + 'F1024' + 'F2048' +]) +param skuName string = 'F2' + +@description('List of admin members (UPNs for users, object IDs for service principals).') +param adminMembers array + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Reference +// ============================================================================ + +module fabricCapacity 'br/public:avm/res/fabric/capacity:0.1.2' = { + name: take('avm.res.fabric.capacity.${name}', 64) + params: { + name: name + location: location + skuName: skuName + adminMembers: adminMembers + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the deployed Fabric capacity.') +output name string = fabricCapacity.outputs.name + +@description('The resource ID of the deployed Fabric capacity.') +output resourceId string = fabricCapacity.outputs.resourceId + +@description('The resource group name.') +output resourceGroupName string = fabricCapacity.outputs.resourceGroupName + +@description('The location of the deployed Fabric capacity.') +output location string = fabricCapacity.outputs.location diff --git a/infra/avm/modules/identity/cross-scope-role-assignment.bicep b/infra/avm/modules/identity/cross-scope-role-assignment.bicep new file mode 100644 index 00000000..8ed9e333 --- /dev/null +++ b/infra/avm/modules/identity/cross-scope-role-assignment.bicep @@ -0,0 +1,37 @@ +// ============================================================================ +// cross-scope-role-assignment.bicep +// Description: Reusable helper that creates a single role assignment scoped +// to an existing AI Services resource. Used for cross-resource- +// group RBAC where the AI Services lives in a different RG. +// ============================================================================ + +@description('The principal ID to assign the role to.') +param principalId string + +@description('The resource ID of the role definition to assign.') +param roleDefinitionId string + +@description('A unique name for the role assignment.') +param roleAssignmentName string + +@description('The name of the AI Foundry account to scope the role assignment to.') +param aiFoundryName string + +@description('The principal type of the identity being assigned.') +@allowed(['ServicePrincipal', 'User']) +param principalType string = 'ServicePrincipal' + +// Reference the existing AI Foundry resource in this resource group +resource aiFoundryAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiFoundryName +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: roleAssignmentName + scope: aiFoundryAccount + properties: { + roleDefinitionId: roleDefinitionId + principalId: principalId + principalType: principalType + } +} diff --git a/infra/avm/modules/identity/managed-identity.bicep b/infra/avm/modules/identity/managed-identity.bicep new file mode 100644 index 00000000..f2d264ee --- /dev/null +++ b/infra/avm/modules/identity/managed-identity.bicep @@ -0,0 +1,49 @@ +// ============================================================================ +// Module: Managed Identity +// Description: AVM wrapper for User-Assigned Managed Identity +// AVM Module: avm/res/managed-identity/user-assigned-identity +// Usage: Call this module once per identity from main.bicep +// ============================================================================ + +@description('Solution name used for resource naming.') +param solutionName string + +@description('Name of the managed identity.') +param identityName string = 'id-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module managedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { + name: take('avm.res.managed-identity.user-assigned-identity.${identityName}', 64) + params: { + name: identityName + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the managed identity.') +output resourceId string = managedIdentity.outputs.resourceId + +@description('Principal ID of the managed identity.') +output principalId string = managedIdentity.outputs.principalId + +@description('Client ID of the managed identity.') +output clientId string = managedIdentity.outputs.clientId + +@description('Name of the managed identity.') +output name string = managedIdentity.outputs.name diff --git a/infra/avm/modules/identity/role-assignments.bicep b/infra/avm/modules/identity/role-assignments.bicep new file mode 100644 index 00000000..399e4ae1 --- /dev/null +++ b/infra/avm/modules/identity/role-assignments.bicep @@ -0,0 +1,280 @@ +// ============================================================================ +// Module: Role Assignments (centralized — all cross-service + data plane RBAC) +// Description: RG-level, cross-service, and data-plane role assignments. +// One place to audit "who has access to what". +// ============================================================================ + +// ============================================================================ +// Parameters +// ============================================================================ + +@description('Solution name suffix for generating unique role assignment GUIDs.') +param solutionName string = '' + +@description('Whether to use an existing AI project (true) or create new (false).') +param useExistingAIProject bool = false + +@description('Resource ID of the existing AI project (for deriving AI Services name/sub/RG).') +param existingFoundryProjectResourceId string = '' + +// --- Identity Principal IDs --- + +@description('Principal ID of the AI project identity.') +param aiProjectPrincipalId string = '' + +@description('Principal ID of the existing AI project identity (for cross-service roles).') +param existingAiProjectPrincipalId string = '' + +@description('Principal ID of the AI Search identity.') +param aiSearchPrincipalId string = '' + +@description('Principal ID of the backend App Service system-assigned identity (empty if not deployed).') +param backendAppServicePrincipalId string = '' + +// --- Resource References --- + +@description('Resource ID of the AI Foundry account (empty if not deployed — new project path).') +param aiFoundryResourceId string = '' + +@description('Resource ID of the AI Search service (empty if not deployed).') +param aiSearchResourceId string = '' + +@description('Resource ID of the Storage Account (empty if not deployed).') +param storageAccountResourceId string = '' + +@description('Name of the Cosmos DB account (empty if not deployed).') +param cosmosDbAccountName string = '' + +// ============================================================================ +// Derived Variables +// ============================================================================ + +var existingAIFoundryName = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[8] : '' +var existingAIFoundrySubscription = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[2] : subscription().subscriptionId +var existingAIFoundryResourceGroup = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[4] : resourceGroup().name + +// ============================================================================ +// Role Definitions +// ============================================================================ + +var roleDefinitions = { + azureAiUser: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Foundry User + cognitiveServicesUser: 'a97b65f3-24c7-4388-baec-2e87135dc908' + cognitiveServicesOpenAIUser: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + searchIndexDataReader: '1407120a-92aa-4202-b7e9-c0e197c71c8f' + searchServiceContributor: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' + storageBlobDataContributor: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + storageBlobDataReader: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +} + +// ============================================================================ +// Existing Resource References +// ============================================================================ + +resource aiFoundryAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if (!empty(aiFoundryResourceId)) { + name: last(split(aiFoundryResourceId, '/')) +} + +resource aiSearchService 'Microsoft.Search/searchServices@2025-05-01' existing = if (!empty(aiSearchResourceId)) { + name: last(split(aiSearchResourceId, '/')) +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' existing = if (!empty(storageAccountResourceId)) { + name: last(split(storageAccountResourceId, '/')) +} + +resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + name: cosmosDbAccountName +} + +resource cosmosContributorRoleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + parent: cosmosAccount + name: '00000000-0000-0000-0000-000000000002' // Cosmos DB Built-in Data Contributor +} + +// ============================================================================ +// 1. AI SERVICES ROLE ASSIGNMENTS +// Cross-service roles scoped to AI Foundry account +// ============================================================================ + +// AI Search → Cognitive Services OpenAI User on AI Foundry (new project, same RG) +resource assignOpenAIRoleToAISearch 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiSearchPrincipalId) && !empty(aiFoundryResourceId)) { + name: guid(aiFoundryAccount.id, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + scope: aiFoundryAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Cognitive Services OpenAI User on existing AI Foundry (cross-scope) +module assignOpenAIToSearchExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(aiSearchPrincipalId)) { + name: 'assignOpenAIRoleToAISearchExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + roleAssignmentName: guid(existingAIFoundryName, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + aiFoundryName: existingAIFoundryName + } +} + +// Backend App Service → Foundry User on AI Foundry (new project, same RG) +resource backendAppAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiFoundryResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiFoundryAccount.id, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + scope: aiFoundryAccount + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Foundry User on existing AI Foundry (cross-scope) +module backendAppAiUserExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(backendAppServicePrincipalId)) { + name: 'assignAiUserRoleToBackendExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + roleAssignmentName: guid(existingAIFoundryName, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + aiFoundryName: existingAIFoundryName + } +} + +// ============================================================================ +// 2. SEARCH SERVICE ROLE ASSIGNMENTS +// AI Project and Backend identities → AI Search +// ============================================================================ + +// AI Project → Search Index Data Reader on AI Search (new project) +resource projectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Search Service Contributor on AI Search (new project) +resource projectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Index Data Reader on AI Search +resource existingProjectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Service Contributor on AI Search +resource existingProjectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Search Index Data Reader on AI Search +resource backendAppSearchReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiSearchService.id, backendAppServicePrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 3. STORAGE ROLE ASSIGNMENTS +// AI Project, AI Search, and Existing Project identities → Storage +// ============================================================================ + +// AI Project → Storage Blob Data Contributor (new project) +resource projectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Storage Blob Data Reader (new project) +resource projectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Contributor +resource existingProjectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Reader +resource existingProjectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Storage Blob Data Reader +resource searchStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiSearchPrincipalId)) { + name: guid(storageAccount.id, aiSearchPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 4. COSMOS DB ROLE ASSIGNMENTS +// Backend App Service → Cosmos DB (data-plane, uses sqlRoleAssignments) +// ============================================================================ + +resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) { + parent: cosmosAccount + name: guid(cosmosContributorRoleDefinition.id, cosmosAccount.id, backendAppServicePrincipalId) + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: cosmosContributorRoleDefinition.id + scope: cosmosAccount.id + } +} + diff --git a/infra/avm/modules/monitoring/app-insights.bicep b/infra/avm/modules/monitoring/app-insights.bicep new file mode 100644 index 00000000..b726ae81 --- /dev/null +++ b/infra/avm/modules/monitoring/app-insights.bicep @@ -0,0 +1,76 @@ +// ============================================================================ +// Module: Application Insights +// Description: AVM wrapper for Application Insights with WAF alignment +// AVM Module: avm/res/insights/component:0.7.1 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/application-insights +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}.') +param name string = 'appi-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace to link to.') +param workspaceResourceId string + +@description('Application type.') +param applicationType string = 'web' + +@description('Retention period in days. WAF recommends 365.') +param retentionInDays int = 365 + +@description('Disable IP masking for security. WAF recommends false.') +param disableIpMasking bool = false + +@description('Flow type for Application Insights.') +param flowType string = 'Bluefield' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Kind of Application Insights resource.') +param kind string = 'web' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module appInsights 'br/public:avm/res/insights/component:0.7.1' = { + name: take('avm.res.insights.component.${name}', 64) + params: { + name: name + location: location + tags: tags + workspaceResourceId: workspaceResourceId + kind: kind + applicationType: applicationType + enableTelemetry: enableTelemetry + retentionInDays: retentionInDays + disableIpMasking: disableIpMasking + flowType: flowType + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Application Insights instance.') +output resourceId string = appInsights.outputs.resourceId + +@description('Name of the Application Insights instance.') +output name string = appInsights.outputs.name + +@description('Instrumentation key for the Application Insights instance.') +output instrumentationKey string = appInsights.outputs.instrumentationKey + +@description('Connection string for the Application Insights instance.') +output connectionString string = appInsights.outputs.connectionString + +@description('Application ID of the Application Insights instance.') +output applicationId string = appInsights.outputs.applicationId diff --git a/infra/avm/modules/monitoring/data-collection-rule.bicep b/infra/avm/modules/monitoring/data-collection-rule.bicep new file mode 100644 index 00000000..c1fd7606 --- /dev/null +++ b/infra/avm/modules/monitoring/data-collection-rule.bicep @@ -0,0 +1,149 @@ +// ============================================================================ +// Module: Data Collection Rule +// Description: AVM wrapper for Azure Monitor Data Collection Rule +// AVM Module: avm/res/insights/data-collection-rule +// WAF: Monitoring for VM observability +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the data collection rule. Defaults to dcr-{solutionName}.') +param name string = 'dcr-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace destination.') +param logAnalyticsWorkspaceResourceId string + +@description('Name of the Log Analytics workspace (used for destination naming).') +param logAnalyticsWorkspaceName string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var dcrLogAnalyticsDestinationName = !empty(logAnalyticsWorkspaceName) ? 'la-${logAnalyticsWorkspaceName}-destination' : 'la-${name}-destination' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:0.11.0' = { + name: take('avm.res.insights.data-collection-rule.${name}', 64) + params: { + name: name + tags: tags + enableTelemetry: enableTelemetry + location: location + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + performanceCounters: [ + { + streams: ['Microsoft-Perf'] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' + } + ] + windowsEventLogs: [ + { + name: 'SecurityAuditEvents' + streams: ['Microsoft-WindowsEvent'] + xPathQueries: [ + 'Security!*[System[(EventID=4624 or EventID=4625)]]' + ] + } + { + name: 'AuditSuccessFailure' + streams: ['Microsoft-Event'] + xPathQueries: [ + 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' + ] + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: dcrLogAnalyticsDestinationName + } + ] + } + dataFlows: [ + { + streams: ['Microsoft-Perf'] + destinations: [dcrLogAnalyticsDestinationName] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + { + streams: ['Microsoft-Event'] + destinations: [dcrLogAnalyticsDestinationName] + transformKql: 'source' + outputStream: 'Microsoft-Event' + } + ] + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the data collection rule.') +output resourceId string = dataCollectionRule.outputs.resourceId + +@description('Name of the data collection rule.') +output name string = dataCollectionRule.outputs.name diff --git a/infra/avm/modules/monitoring/log-analytics.bicep b/infra/avm/modules/monitoring/log-analytics.bicep new file mode 100644 index 00000000..3b231240 --- /dev/null +++ b/infra/avm/modules/monitoring/log-analytics.bicep @@ -0,0 +1,90 @@ +// ============================================================================ +// Module: Log Analytics Workspace +// Description: AVM wrapper for Log Analytics Workspace with WAF alignment +// AVM Module: avm/res/operational-insights/workspace:0.15.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-log-analytics +// Note: This module only handles NEW workspace creation. +// Existing workspace logic is handled in main.bicep. +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}.') +param name string = 'log-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Retention period in days. WAF recommends 365.') +param retentionInDays int = 365 + +@description('SKU name for the workspace.') +param skuName string = 'PerGB2018' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Private Networking --- +@description('Public network access for ingestion.') +param publicNetworkAccessForIngestion string = 'Enabled' + +@description('Public network access for query.') +param publicNetworkAccessForQuery string = 'Enabled' + +// --- WAF: Redundancy --- +@description('Enable workspace replication for redundancy.') +param enableReplication bool = false + +@description('Replication location (paired region).') +param replicationLocation string = '' + +@description('Daily quota in GB. WAF recommends 150 GB/day as starting point.') +param dailyQuotaGb string = '' + +// --- WAF: Monitoring (VM data sources for private networking) --- +@description('Data sources for VM monitoring (Windows events, perf counters).') +param dataSources array = [] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module workspace 'br/public:avm/res/operational-insights/workspace:0.15.0' = { + name: take('avm.res.operational-insights.workspace.${name}', 64) + params: { + name: name + location: location + tags: tags + dataRetention: retentionInDays + skuName: skuName + enableTelemetry: enableTelemetry + features: { enableLogAccessUsingOnlyResourcePermissions: true } + diagnosticSettings: [{ useThisWorkspace: true }] + publicNetworkAccessForIngestion: publicNetworkAccessForIngestion + publicNetworkAccessForQuery: publicNetworkAccessForQuery + dailyQuotaGb: !empty(dailyQuotaGb) ? dailyQuotaGb : null + replication: enableReplication ? { + enabled: true + location: replicationLocation + } : null + dataSources: !empty(dataSources) ? dataSources : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Log Analytics workspace.') +output resourceId string = workspace.outputs.resourceId + +@description('Name of the Log Analytics workspace.') +output name string = workspace.outputs.name + +@description('Location of the workspace.') +output location string = location + +@description('Log Analytics workspace customer ID.') +output logAnalyticsWorkspaceId string = workspace.outputs.logAnalyticsWorkspaceId diff --git a/infra/avm/modules/monitoring/portal-dashboard.bicep b/infra/avm/modules/monitoring/portal-dashboard.bicep new file mode 100644 index 00000000..5bf9148d --- /dev/null +++ b/infra/avm/modules/monitoring/portal-dashboard.bicep @@ -0,0 +1,53 @@ +// ============================================================================ +// Module: Portal Dashboard (Application Insights) +// Description: AVM wrapper for Azure Portal Dashboard +// AVM Module: avm/res/portal/dashboard:0.3.2 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the dashboard.') +param name string = 'dash-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Lenses (tile groups) to display on the dashboard.') +param lenses array = [] + +@description('Dashboard metadata (time range, filters, etc.).') +param metadata object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module dashboard 'br/public:avm/res/portal/dashboard:0.3.2' = { + name: take('avm.res.portal.dashboard.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + lenses: lenses + metadata: !empty(metadata) ? metadata : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the dashboard.') +output resourceId string = dashboard.outputs.resourceId + +@description('Name of the dashboard.') +output name string = dashboard.outputs.name + +@description('Resource group the dashboard was deployed to.') +output resourceGroupName string = dashboard.outputs.resourceGroupName diff --git a/infra/avm/modules/networking/bastion-host.bicep b/infra/avm/modules/networking/bastion-host.bicep new file mode 100644 index 00000000..bf524087 --- /dev/null +++ b/infra/avm/modules/networking/bastion-host.bicep @@ -0,0 +1,85 @@ +// ============================================================================ +// Module: Bastion Host +// Description: AVM wrapper for Azure Bastion Host +// AVM Module: avm/res/network/bastion-host +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +var name = 'bas-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Resource ID of the virtual network.') +param virtualNetworkResourceId string + +@description('Optional. Diagnostic settings for the resource.') +param diagnosticSettings array? + +@description('SKU name for the Bastion Host.') +param skuName string = 'Standard' + +@description('Number of scale units.') +param scaleUnits int = 4 + +@description('Disable copy/paste functionality.') +param disableCopyPaste bool = true + +@description('Enable file copy functionality.') +param enableFileCopy bool = false + +@description('Enable IP Connect functionality.') +param enableIpConnect bool = false + +@description('Enable shareable link functionality.') +param enableShareableLink bool = false + +@description('Availability zones for the Bastion Host public IP. Pass empty array to disable zone redundancy.') +param availabilityZones array = [] + +@description('Optional. Diagnostic settings for the public IP address.') +param publicIPDiagnosticSettings array? + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = { + name: take('avm.res.network.bastion-host.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + virtualNetworkResourceId: virtualNetworkResourceId + availabilityZones: availabilityZones + publicIPAddressObject: { + name: 'pip-${name}' + diagnosticSettings: publicIPDiagnosticSettings + tags: tags + } + disableCopyPaste: disableCopyPaste + enableFileCopy: enableFileCopy + enableIpConnect: enableIpConnect + enableShareableLink: enableShareableLink + scaleUnits: scaleUnits + diagnosticSettings: diagnosticSettings + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Bastion Host.') +output resourceId string = bastionHost.outputs.resourceId + +@description('Name of the Bastion Host.') +output name string = bastionHost.outputs.name diff --git a/infra/avm/modules/networking/private-dns-zone.bicep b/infra/avm/modules/networking/private-dns-zone.bicep new file mode 100644 index 00000000..24bd2892 --- /dev/null +++ b/infra/avm/modules/networking/private-dns-zone.bicep @@ -0,0 +1,40 @@ +// ============================================================================ +// Module: Private DNS Zone +// Description: AVM wrapper for Azure Private DNS Zone +// AVM Module: avm/res/network/private-dns-zone +// Usage: Call once per DNS zone from main.bicep +// ============================================================================ + +@description('Name of the private DNS zone (e.g., privatelink.cognitiveservices.azure.com).') +param name string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Virtual network links to associate with the DNS zone.') +param virtualNetworkLinks array = [] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module privateDnsZone 'br/public:avm/res/network/private-dns-zone:0.8.1' = { + name: take('avm.res.network.private-dns-zone.${name}', 64) + params: { + name: name + tags: tags + enableTelemetry: enableTelemetry + virtualNetworkLinks: virtualNetworkLinks + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the private DNS zone.') +output resourceId string = privateDnsZone.outputs.resourceId + +@description('Name of the private DNS zone.') +output name string = privateDnsZone.outputs.name diff --git a/infra/avm/modules/networking/private-endpoint.bicep b/infra/avm/modules/networking/private-endpoint.bicep new file mode 100644 index 00000000..04bfff07 --- /dev/null +++ b/infra/avm/modules/networking/private-endpoint.bicep @@ -0,0 +1,52 @@ +// ============================================================================ +// Module: Private Endpoint +// Description: AVM wrapper for Azure Private Endpoint +// AVM Module: avm/res/network/private-endpoint +// Usage: Call once per private endpoint from main.bicep +// ============================================================================ + +@description('Name of the private endpoint.') +param name string + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Custom NIC name for the private endpoint.') +param customNetworkInterfaceName string = '' + +@description('Resource ID of the subnet for the private endpoint.') +param subnetResourceId string + +@description('Private link service connections configuration.') +param privateLinkServiceConnections array + +@description('Optional. Private DNS zone group configuration.') +param privateDnsZoneGroup object? + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module privateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = { + name: take('avm.res.network.private-endpoint.${name}', 64) + params: { + name: name + location: location + tags: tags + customNetworkInterfaceName: !empty(customNetworkInterfaceName) ? customNetworkInterfaceName : 'nic-${name}' + subnetResourceId: subnetResourceId + privateLinkServiceConnections: privateLinkServiceConnections + privateDnsZoneGroup: privateDnsZoneGroup + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the private endpoint.') +output resourceId string = privateEndpoint.outputs.resourceId + +@description('Name of the private endpoint.') +output name string = privateEndpoint.outputs.name diff --git a/infra/avm/modules/networking/virtual-network.bicep b/infra/avm/modules/networking/virtual-network.bicep new file mode 100644 index 00000000..241e39d5 --- /dev/null +++ b/infra/avm/modules/networking/virtual-network.bicep @@ -0,0 +1,303 @@ +// ============================================================================ +// Module: Virtual Network +// Description: VNet, Subnets, and NSGs using AVM modules. +// Each subnet gets its own NSG. Subnet config is passed as param. +// AVM Modules: +// - avm/res/network/network-security-group:0.5.3 +// - avm/res/network/virtual-network:0.8.0 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +var name = 'vnet-${solutionName}' + +@description('Azure region for the resource.') +param location string = resourceGroup().location + +@description('Address prefixes for the virtual network.') +param addressPrefixes array + +@description('Subnet configurations.') +param subnets subnetType[] = [ + { + name: 'backend' + addressPrefixes: ['10.0.0.0/27'] + networkSecurityGroup: { + name: 'nsg-backend' + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: ['22', '3389'] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } + } + { + name: 'webserverfarm' + addressPrefixes: ['10.0.4.0/27'] + delegation: 'Microsoft.Web/serverfarms' + privateEndpointNetworkPolicies: 'Enabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroup: { + name: 'nsg-webserverfarm' + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: ['22', '3389'] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } + } + { + name: 'administration' + addressPrefixes: ['10.0.0.32/27'] + networkSecurityGroup: { + name: 'nsg-administration' + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: ['22', '3389'] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } + } + { + name: 'AzureBastionSubnet' + addressPrefixes: ['10.0.0.64/26'] + networkSecurityGroup: { + name: 'nsg-bastion' + securityRules: [ + { + name: 'AllowGatewayManager' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 2702 + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'GatewayManager' + destinationAddressPrefix: '*' + } + } + { + name: 'AllowHttpsInBound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 2703 + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'Internet' + destinationAddressPrefix: '*' + } + } + { + name: 'AllowSshRdpOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 100 + protocol: '*' + sourcePortRange: '*' + destinationPortRanges: ['22', '3389'] + sourceAddressPrefix: '*' + destinationAddressPrefix: 'VirtualNetwork' + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 110 + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: '*' + destinationAddressPrefix: 'AzureCloud' + } + } + ] + } + } +] + +@description('Tags to apply to the resources.') +param tags object = {} + +@description('Resource ID of the Log Analytics Workspace for diagnostics.') +param logAnalyticsWorkspaceId string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Suffix for resource naming.') +param resourceSuffix string + +// ============================================================================ +// NSGs — one per subnet +// ============================================================================ +@batchSize(1) +module nsgs 'br/public:avm/res/network/network-security-group:0.5.3' = [ + for (subnet, i) in subnets: if (!empty(subnet.?networkSecurityGroup)) { + name: take('avm.res.network.nsg.${subnet.?networkSecurityGroup.name}.${resourceSuffix}', 64) + params: { + name: '${subnet.?networkSecurityGroup.name}-${resourceSuffix}' + location: location + securityRules: subnet.?networkSecurityGroup.securityRules + tags: tags + enableTelemetry: enableTelemetry + } + } +] + +// ============================================================================ +// Virtual Network + Subnets +// ============================================================================ +module virtualNetwork 'br/public:avm/res/network/virtual-network:0.8.0' = { + name: take('avm.res.network.virtual-network.${name}', 64) + params: { + name: name + location: location + addressPrefixes: addressPrefixes + subnets: [ + for (subnet, i) in subnets: { + name: subnet.name + addressPrefixes: subnet.?addressPrefixes + networkSecurityGroupResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null + privateEndpointNetworkPolicies: subnet.?privateEndpointNetworkPolicies + privateLinkServiceNetworkPolicies: subnet.?privateLinkServiceNetworkPolicies + delegation: subnet.?delegation + } + ] + diagnosticSettings: [ + { + name: 'vnetDiagnostics' + workspaceResourceId: logAnalyticsWorkspaceId + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + metricCategories: [ + { + category: 'AllMetrics' + enabled: true + } + ] + } + ] + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +output name string = virtualNetwork.outputs.name +output resourceId string = virtualNetwork.outputs.resourceId + +output subnets subnetOutputType[] = [ + for (subnet, i) in subnets: { + name: subnet.name + resourceId: virtualNetwork.outputs.subnetResourceIds[i] + nsgName: !empty(subnet.?networkSecurityGroup) ? subnet.?networkSecurityGroup.name : null + nsgResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null + } +] + +// Individual subnet outputs for backward compatibility +output backendSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'backend') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'backend')] + : '' +output webserverfarmSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'webserverfarm') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'webserverfarm')] + : '' +output administrationSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'administration') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'administration')] + : '' +output bastionSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'AzureBastionSubnet') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'AzureBastionSubnet')] + : '' + +// ============================================================================ +// Custom Types +// ============================================================================ +@export() +@description('Subnet output type') +type subnetOutputType = { + @description('The name of the subnet.') + name: string + @description('The resource ID of the subnet.') + resourceId: string + @description('The name of the associated NSG, if any.') + nsgName: string? + @description('The resource ID of the associated NSG, if any.') + nsgResourceId: string? +} + +@export() +@description('Subnet configuration type') +type subnetType = { + @description('Required. The name of the subnet.') + name: string + @description('Required. Address prefixes for the subnet.') + addressPrefixes: string[] + @description('Optional. Delegation for the subnet.') + delegation: string? + @description('Optional. Private endpoint network policies.') + privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? + @description('Optional. Private link service network policies.') + privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? + @description('Optional. NSG configuration for the subnet.') + networkSecurityGroup: networkSecurityGroupType? + @description('Optional. Route table resource ID.') + routeTableResourceId: string? + @description('Optional. Service endpoint policies.') + serviceEndpointPolicies: object[]? + @description('Optional. Service endpoints to enable.') + serviceEndpoints: string[]? + @description('Optional. Disable default outbound connectivity.') + defaultOutboundAccess: bool? +} + +@export() +@description('NSG configuration type') +type networkSecurityGroupType = { + @description('Required. The name of the NSG.') + name: string + @description('Required. Security rules for the NSG.') + securityRules: object[] +} diff --git a/infra/avm/modules/security/key-vault.bicep b/infra/avm/modules/security/key-vault.bicep new file mode 100644 index 00000000..924eea5b --- /dev/null +++ b/infra/avm/modules/security/key-vault.bicep @@ -0,0 +1,109 @@ +// ============================================================================ +// Module: Azure Key Vault (AVM) +// AVM Module: avm/res/key-vault/vault:0.12.1 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Optional. Override name for the Key Vault. Defaults to kv-{solutionName}.') +param name string = take('kv-${solutionName}', 24) + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the key vault.') +@allowed(['standard', 'premium']) +param sku string = 'standard' + +@description('Enable RBAC authorization.') +param enableRbacAuthorization bool = true + +@description('Enable soft delete.') +param enableSoftDelete bool = true + +@description('Soft delete retention in days.') +param softDeleteRetentionInDays int = 90 + +@description('Enable purge protection.') +param enablePurgeProtection bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Secrets to store in the vault (name/value pairs).') +param secrets array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('Role assignments.') +param roleAssignments array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +// ============================================================================ +// Key Vault (AVM) +// ============================================================================ + +var secretItems = [for secret in secrets: { + name: secret.name + value: secret.value +}] + +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +module keyVault 'br/public:avm/res/key-vault/vault:0.12.1' = { + name: take('avm.res.keyvault.vault.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: sku + enableRbacAuthorization: enableRbacAuthorization + enableSoftDelete: enableSoftDelete + softDeleteRetentionInDays: softDeleteRetentionInDays + enablePurgeProtection: enablePurgeProtection + publicNetworkAccess: publicNetworkAccess + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + secrets: !empty(secrets) ? secretItems : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the key vault.') +output name string = keyVault.outputs.name + +@description('The URI of the key vault.') +output uri string = keyVault.outputs.uri + +@description('The resource ID of the key vault.') +output resourceId string = keyVault.outputs.resourceId diff --git a/infra/bicep/modules/ai/ai-foundry-connection.bicep b/infra/bicep/modules/ai/ai-foundry-connection.bicep new file mode 100644 index 00000000..b0af1f6d --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry-connection.bicep @@ -0,0 +1,84 @@ +// ============================================================================ +// Module: AI Foundry Project Connection (Single) — Vanilla Bicep +// Description: Creates a single connection on an AI Foundry project. +// Generic, reusable — call once per connection type from main.bicep. +// Supports any connection category (CognitiveSearch, AzureBlob, +// AppInsights, RemoteTool, etc.) via parameterized properties. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name of the AI Foundry project.') +param projectName string + +@description('Required. Solution name suffix used to generate the connection name.') +param solutionName string + +@description('Optional. Connection name. Defaults to lowercase category with solution suffix.') +param connectionName string = toLower('${category}-connection-${solutionName}') + +@description('Required. Connection category (e.g., CognitiveSearch, AzureBlob, AppInsights, RemoteTool).') +param category string + +@description('Required. Connection target (URL or resource ID).') +param target string + +@description('Required. Authentication type (e.g., AAD, ApiKey, ProjectManagedIdentity).') +param authType string + +@description('Optional. Whether the connection is shared to all project users.') +param isSharedToAll bool = true + +@description('Optional. Whether this is the default connection for its category.') +param isDefault bool = false + +@description('Optional. Connection metadata object.') +param metadata object = {} + +@secure() +@description('Optional. Credentials key (for ApiKey auth type).') +param credentialsKey string = '' + +// ============================================================================ +// Existing Resource References +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: aiServicesAccount + name: projectName +} + +// ============================================================================ +// Connection +// ============================================================================ +var baseProperties = { + category: category + target: target + authType: authType + isSharedToAll: isSharedToAll + metadata: metadata +} + +var optionalDefault = isDefault ? { isDefault: true } : {} +var optionalCredentials = !empty(credentialsKey) ? { credentials: { key: credentialsKey } } : {} + +resource connection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-12-01' = { + parent: aiProject + name: connectionName + properties: any(union(baseProperties, optionalDefault, optionalCredentials)) +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Connection name.') +output connectionName string = connection.name + +@description('Connection resource ID.') +output connectionId string = connection.id diff --git a/infra/bicep/modules/ai/ai-foundry-model-deployment.bicep b/infra/bicep/modules/ai/ai-foundry-model-deployment.bicep new file mode 100644 index 00000000..4ed69a72 --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry-model-deployment.bicep @@ -0,0 +1,66 @@ +// ============================================================================ +// Module: Model Deployment — Vanilla Bicep +// Description: Deploys a single AI model to an existing AI Services account. +// Called repetitively from main.bicep for each model in the array. +// Generic, reusable across GSAs. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name for this model deployment.') +param deploymentName string + +@description('Optional. Model format (e.g., OpenAI).') +param modelFormat string = 'OpenAI' + +@description('Required. Model name (e.g., gpt-4o, text-embedding-ada-002).') +param modelName string + +@description('Optional. Model version. Empty string means latest.') +param modelVersion string = '' + +@description('Optional. RAI policy name.') +param raiPolicyName string = 'Microsoft.Default' + +@description('Required. SKU name (e.g., Standard, GlobalStandard).') +param skuName string + +@description('Required. SKU capacity (tokens per minute in thousands).') +param skuCapacity int + +// ============================================================================ +// Model Deployment +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource modelDeployment 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { + parent: aiServicesAccount + name: deploymentName + properties: { + model: { + format: modelFormat + name: modelName + version: !empty(modelVersion) ? modelVersion : null + } + raiPolicyName: raiPolicyName + } + sku: { + name: skuName + capacity: skuCapacity + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Name of the deployed model.') +output name string = modelDeployment.name + +@description('Resource ID of the model deployment.') +output resourceId string = modelDeployment.id diff --git a/infra/bicep/modules/ai/ai-foundry-project.bicep b/infra/bicep/modules/ai/ai-foundry-project.bicep new file mode 100644 index 00000000..9d0dd61f --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry-project.bicep @@ -0,0 +1,111 @@ +// ============================================================================ +// Module: AI Foundry Project (Account + Project) — Vanilla Bicep +// Description: Creates an Azure AI Services account and AI Foundry project. +// Generic, reusable across GSAs — no app-specific parameters. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Solution name suffix used to generate resource names.') +param solutionName string + +@description('Optional. Override name for the AI Services account. Defaults to aif-{solutionName}.') +param name string = 'aif-${solutionName}' + +@description('Optional. Override name for the AI Foundry project. Defaults to proj-{solutionName}.') +param projectName string = 'proj-${solutionName}' + +@description('Required. Azure region for the resources.') +param location string + +@description('Optional. Tags to apply to resources.') +param tags object = {} + +@description('Optional. SKU name for the AI Services account.') +param skuName string = 'S0' + +@description('Optional. Whether to disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Optional. Whether to allow project management (AI Foundry hub).') +param allowProjectManagement bool = true + +@description('Optional. Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Managed identity type for the resources.') +@allowed(['SystemAssigned', 'UserAssigned', 'SystemAssigned, UserAssigned', 'None']) +param identityType string = 'SystemAssigned' + +@description('Optional. Network ACLs default action.') +@allowed(['Allow', 'Deny']) +param networkAclsDefaultAction string = 'Allow' + +// ============================================================================ +// AI Services Account +// ============================================================================ +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + } + kind: 'AIServices' + identity: { + type: identityType + } + properties: { + allowProjectManagement: allowProjectManagement + customSubDomainName: name + networkAcls: { + defaultAction: networkAclsDefaultAction + virtualNetworkRules: [] + ipRules: [] + } + publicNetworkAccess: publicNetworkAccess + disableLocalAuth: disableLocalAuth + } +} + +// ============================================================================ +// AI Foundry Project +// ============================================================================ +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { + parent: aiServices + name: projectName + location: location + kind: 'AIServices' + identity: { + type: identityType + } + properties: {} +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the AI Services account.') +output resourceId string = aiServices.id + +@description('Name of the AI Services account.') +output name string = aiServices.name + +@description('Endpoint of the AI Services account (OpenAI Language Model Instance API).') +output endpoint string = aiServices.properties.endpoints['OpenAI Language Model Instance API'] + +@description('System-assigned identity principal ID of the AI Services account.') +output principalId string = aiServices.identity.principalId + +@description('Resource ID of the AI Foundry project.') +output projectResourceId string = aiProject.id + +@description('Name of the AI Foundry project.') +output projectName string = aiProject.name + +@description('AI Foundry project endpoint.') +output projectEndpoint string = aiProject.properties.endpoints['AI Foundry API'] + +@description('System-assigned identity principal ID of the project.') +output projectIdentityPrincipalId string = aiProject.identity.principalId diff --git a/infra/bicep/modules/ai/ai-foundry.bicep b/infra/bicep/modules/ai/ai-foundry.bicep new file mode 100644 index 00000000..35cbb0f2 --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry.bicep @@ -0,0 +1,74 @@ +// ============================================================================ +// Module: Azure AI Foundry (Cognitive Services Account) +// Description: Deploys an Azure AI Services account with AI Foundry capabilities. +// ============================================================================ + +@description('Required. Name of the AI Services account.') +param name string + +@description('Required. Azure region for the resource.') +param location string + +@description('Optional. Principal IDs to assign Cognitive Services OpenAI User role.') +param principalIds array = [] + +@description('Optional. Whether public network access is allowed.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Tags to apply to the resource.') +param tags object = {} + +resource aiServices 'Microsoft.CognitiveServices/accounts@2024-10-01' = { + name: name + location: location + tags: tags + kind: 'AIServices' + identity: { + type: 'SystemAssigned' + } + sku: { + name: 'S0' + } + properties: { + customSubDomainName: name + publicNetworkAccess: publicNetworkAccess + disableLocalAuth: true + allowProjectManagement: true + networkAcls: { + bypass: 'AzureServices' + defaultAction: publicNetworkAccess == 'Enabled' ? 'Allow' : 'Deny' + } + } +} + +// Assign Cognitive Services OpenAI User role to provided principal IDs +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for principalId in principalIds: { + name: guid(aiServices.id, principalId, 'Cognitive Services OpenAI User') + scope: aiServices + properties: { + principalId: principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a97b65f3-24c7-4388-baec-2e87135dc908' // Cognitive Services OpenAI User + ) + principalType: 'ServicePrincipal' + } + } +] + +@description('The name of the deployed AI Services account.') +output name string = aiServices.name + +@description('The resource ID of the AI Services account.') +output resourceId string = aiServices.id + +@description('The endpoint of the AI Services account.') +output endpoint string = aiServices.properties.endpoint + +@description('The principal ID of the system-assigned managed identity.') +output systemAssignedPrincipalId string = aiServices.identity.principalId diff --git a/infra/bicep/modules/ai/ai-search-identity.bicep b/infra/bicep/modules/ai/ai-search-identity.bicep new file mode 100644 index 00000000..da2309b8 --- /dev/null +++ b/infra/bicep/modules/ai/ai-search-identity.bicep @@ -0,0 +1,65 @@ +// ============================================================================ +// Module: AI Search Identity Update +// Description: Separate deployment that enables managed identity and applies +// full configuration on an existing AI Search service. +// Called by ai-search.bicep as Step 2 of the two-step pattern. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('The name of the existing AI Search service.') +param name string + +@description('The Azure region of the search service.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the search service.') +param skuName string = 'basic' + +@description('Number of replicas.') +param replicaCount int = 1 + +@description('Number of partitions.') +param partitionCount int = 1 + +@description('Hosting mode.') +@allowed(['Default', 'HighDensity']) +param hostingMode string = 'Default' + +@description('Semantic search tier.') +param semanticSearch string = 'free' + +@description('Whether to disable local authentication.') +param disableLocalAuth bool = true + +@description('Managed identity type for the search service.') +param managedIdentityType string = 'SystemAssigned' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +resource searchServiceUpdate 'Microsoft.Search/searchServices@2025-05-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + } + identity: { + type: managedIdentityType + } + properties: { + replicaCount: replicaCount + partitionCount: partitionCount + hostingMode: hostingMode + semanticSearch: semanticSearch + disableLocalAuth: disableLocalAuth + publicNetworkAccess: publicNetworkAccess + } +} + +@description('The principal ID of the AI Search system-assigned managed identity.') +output systemAssignedMIPrincipalId string = searchServiceUpdate.identity.principalId diff --git a/infra/bicep/modules/ai/ai-search.bicep b/infra/bicep/modules/ai/ai-search.bicep new file mode 100644 index 00000000..06c31880 --- /dev/null +++ b/infra/bicep/modules/ai/ai-search.bicep @@ -0,0 +1,97 @@ +// ============================================================================ +// Module: AI Search +// Description: Deploys Azure AI Search with a two-step pattern: +// Step 1: Plain Bicep resource for fast initial creation (name, location, SKU) +// Step 2: Separate module deployment to enable managed identity & full config +// This reduces deployment time by making the resource available immediately +// while identity enablement proceeds as a separate ARM deployment. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Solution name suffix used to derive the resource name.') +@minLength(3) +param solutionName string + +@description('Optional. Override name for the search service. Defaults to srch-{solutionName}.') +param name string = 'srch-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the search service.') +@allowed(['free', 'basic', 'standard', 'standard2', 'standard3', 'storage_optimized_l1', 'storage_optimized_l2']) +param skuName string = 'basic' + +@description('Number of replicas.') +param replicaCount int = 1 + +@description('Number of partitions.') +param partitionCount int = 1 + +@description('Hosting mode.') +@allowed(['Default', 'HighDensity']) +param hostingMode string = 'Default' + +@description('Semantic search tier.') +@allowed(['disabled', 'free', 'standard']) +param semanticSearch string = 'free' + +@description('Whether to disable local authentication.') +param disableLocalAuth bool = true + +@description('Managed identity type for the search service.') +param managedIdentityType string = 'SystemAssigned' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// Step 1: Initial resource creation (fast — no identity) +// ============================================================================ +resource aiSearch 'Microsoft.Search/searchServices@2025-05-01' = { + name: name + location: location + sku: { + name: skuName + } +} + +// ============================================================================ +// Step 2: Separate deployment — enables identity & full configuration +// ============================================================================ +module searchServiceUpdate 'ai-search-identity.bicep' = { + name: 'searchServiceUpdate' + params: { + name: aiSearch.name + location: location + tags: tags + skuName: skuName + replicaCount: replicaCount + partitionCount: partitionCount + hostingMode: hostingMode + semanticSearch: semanticSearch + disableLocalAuth: disableLocalAuth + managedIdentityType: managedIdentityType + publicNetworkAccess: publicNetworkAccess + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the AI Search service.') +output resourceId string = aiSearch.id + +@description('Name of the AI Search service.') +output name string = aiSearch.name + +@description('Endpoint URL of the AI Search service.') +output endpoint string = 'https://${aiSearch.name}.search.windows.net' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = searchServiceUpdate.outputs.systemAssignedMIPrincipalId diff --git a/infra/bicep/modules/ai/ai-services.bicep b/infra/bicep/modules/ai/ai-services.bicep new file mode 100644 index 00000000..4c3d6128 --- /dev/null +++ b/infra/bicep/modules/ai/ai-services.bicep @@ -0,0 +1,87 @@ +// ============================================================================ +// Module: Azure AI Services (Generic) +// Description: Deploys Cognitive Services — supports Content Safety, +// Speech, Computer Vision, Document Intelligence, and others. +// API: Microsoft.CognitiveServices/accounts@2025-04-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name prefix for the resource (e.g., cs, speech, cv, docintel).') +param namePrefix string + +@description('The kind of Cognitive Service to deploy.') +@allowed([ + 'ContentSafety' + 'SpeechServices' + 'ComputerVision' + 'FormRecognizer' + 'TextAnalytics' + 'TextTranslation' + 'Face' + 'OpenAI' + 'AIServices' +]) +param kind string + +@description('Optional. Override name for the resource. Defaults to {namePrefix}-{solutionName}.') +param name string = '${namePrefix}-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU for the Cognitive Services account.') +@allowed(['F0', 'S0', 'S1']) +param sku string = 'S0' + +@description('Custom subdomain name for the account.') +param customSubDomainName string = '' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +var effectiveSubDomain = !empty(customSubDomainName) ? customSubDomainName : name + +// ============================================================================ +// Resource +// ============================================================================ +resource aiService 'Microsoft.CognitiveServices/accounts@2025-12-01' = { + name: name + location: location + tags: tags + kind: kind + sku: { + name: sku + } + identity: { + type: 'SystemAssigned' + } + properties: { + customSubDomainName: effectiveSubDomain + publicNetworkAccess: publicNetworkAccess + disableLocalAuth: disableLocalAuth + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AI Services account.') +output name string = aiService.name + +@description('Resource ID of the AI Services account.') +output resourceId string = aiService.id + +@description('Endpoint of the AI Services account.') +output endpoint string = aiService.properties.endpoint + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = aiService.identity.principalId diff --git a/infra/bicep/modules/ai/existing-project-setup.bicep b/infra/bicep/modules/ai/existing-project-setup.bicep new file mode 100644 index 00000000..37cd666d --- /dev/null +++ b/infra/bicep/modules/ai/existing-project-setup.bicep @@ -0,0 +1,51 @@ +// ============================================================================ +// Module: Existing AI Foundry Project Reference — Vanilla Bicep +// Description: References an existing AI Services account and project to +// retrieve their identities. No deployments, no connections. +// Use generic ai-foundry-connection and ai-foundry-model-deployment +// modules for those concerns. +// ============================================================================ + +@description('Required. The name of the existing Cognitive Services account.') +param name string + +@description('Required. The name of the existing AI project.') +param projectName string + +// ============================================================================ +// Existing Resource References +// ============================================================================ + +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: aiServices + name: projectName +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The principal ID of the AI Foundry system-assigned managed identity.') +output aiFoundryPrincipalId string = contains(aiServices, 'identity') && contains(aiServices.identity, 'principalId') ? aiServices.identity.principalId : '' + +@description('The principal ID of the AI Project system-assigned managed identity.') +output aiProjectPrincipalId string = contains(aiProject, 'identity') && contains(aiProject.identity, 'principalId') ? aiProject.identity.principalId : '' + +@description('The name of the AI Services account.') +output aiServicesAccountName string = aiServices.name + +@description('The name of the AI project.') +output aiProjectName string = aiProject.name + +@description('The endpoint URL for the Azure OpenAI service.') +output aiFoundryEndpoint string = 'https://${name}.openai.azure.com/' + +@description('The endpoint URL for the AI Foundry project.') +output projectEndpoint string = 'https://${name}.services.ai.azure.com/api/projects/${projectName}' + +@description('The resource ID of the AI Services account.') +output aiFoundryResourceId string = aiServices.id diff --git a/infra/bicep/modules/compute/app-service-plan.bicep b/infra/bicep/modules/compute/app-service-plan.bicep new file mode 100644 index 00000000..f9409f0c --- /dev/null +++ b/infra/bicep/modules/compute/app-service-plan.bicep @@ -0,0 +1,60 @@ +// ============================================================================ +// Module: App Service Plan +// Description: Creates an Azure App Service Plan +// API: Microsoft.Web/serverfarms@2025-05-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service Plan.') +param name string = 'asp-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the App Service Plan.') +@allowed(['F1', 'D1', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1', 'P2', 'P3', 'P4', 'P0v3', 'P0v4', 'P1v3', 'P1v4', 'P2v3', 'P3v3']) +param skuName string = 'B2' + +@description('Whether the plan is Linux-based.') +param reserved bool = true + +@description('Kind of the App Service Plan.') +param kind string = 'linux' + +@description('Number of instances (workers).') +param skuCapacity int = 1 + +@description('Enable zone redundancy. Requires Premium SKU (P1v3+).') +param zoneRedundant bool = false + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource appServicePlan 'Microsoft.Web/serverfarms@2025-05-01' = { + name: name + location: location + tags: tags + kind: kind + sku: { + name: skuName + capacity: skuCapacity + } + properties: { + reserved: reserved + zoneRedundant: zoneRedundant + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service Plan.') +output resourceId string = appServicePlan.id + +@description('Name of the App Service Plan.') +output name string = appServicePlan.name diff --git a/infra/bicep/modules/compute/app-service.bicep b/infra/bicep/modules/compute/app-service.bicep new file mode 100644 index 00000000..0142878e --- /dev/null +++ b/infra/bicep/modules/compute/app-service.bicep @@ -0,0 +1,111 @@ +// ============================================================================ +// Module: App Service +// Description: Creates an Azure App Service (Web App) +// API: Microsoft.Web/sites@2025-05-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service.') +param name string = solutionName + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Docker image name (e.g., DOCKER|registry.azurecr.io/image:tag).') +param linuxFxVersion string + +@description('Application settings key-value pairs.') +param appSettings object = {} + +@description('Whether to enable Always On.') +param alwaysOn bool = true + +@description('Kind of web app.') +param kind string = 'app,linux' + +@description('Subnet resource ID for VNet integration.') +param virtualNetworkSubnetId string = '' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource appService 'Microsoft.Web/sites@2025-05-01' = { + name: name + location: location + tags: tags + kind: kind + identity: { + type: 'SystemAssigned' + } + properties: { + serverFarmId: serverFarmResourceId + publicNetworkAccess: publicNetworkAccess + virtualNetworkSubnetId: !empty(virtualNetworkSubnetId) ? virtualNetworkSubnetId : null + siteConfig: { + alwaysOn: alwaysOn + ftpsState: 'Disabled' + linuxFxVersion: linuxFxVersion + } + endToEndEncryptionEnabled: true + } + + resource basicPublishingCredentialsPoliciesFtp 'basicPublishingCredentialsPolicies' = { + name: 'ftp' + properties: { + allow: false + } + } + resource basicPublishingCredentialsPoliciesScm 'basicPublishingCredentialsPolicies' = { + name: 'scm' + properties: { + allow: false + } + } +} + +resource configAppSettings 'Microsoft.Web/sites/config@2025-05-01' = { + name: 'appsettings' + parent: appService + properties: appSettings +} + +resource configLogs 'Microsoft.Web/sites/config@2025-05-01' = { + name: 'logs' + parent: appService + properties: { + applicationLogs: { fileSystem: { level: 'Verbose' } } + detailedErrorMessages: { enabled: true } + failedRequestsTracing: { enabled: true } + httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } } + } + dependsOn: [configAppSettings] +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service.') +output resourceId string = appService.id + +@description('Name of the App Service.') +output name string = appService.name + +@description('Default hostname of the App Service.') +output defaultHostname string = appService.properties.defaultHostName + +@description('URL of the App Service.') +output appUrl string = 'https://${appService.properties.defaultHostName}' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = appService.identity.principalId diff --git a/infra/bicep/modules/compute/container-app-environment.bicep b/infra/bicep/modules/compute/container-app-environment.bicep new file mode 100644 index 00000000..c565a158 --- /dev/null +++ b/infra/bicep/modules/compute/container-app-environment.bicep @@ -0,0 +1,63 @@ +// ============================================================================ +// Module: Azure Container Apps Environment +// Description: Creates an Azure Container Apps managed environment +// API: Microsoft.App/managedEnvironments@2024-03-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Container Apps Environment.') +param name string = 'cae-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace.') +param logAnalyticsWorkspaceResourceId string + +@description('Subnet resource ID for VNet integration (optional).') +param infrastructureSubnetId string = '' + +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2024-03-01' = { + name: name + location: location + tags: tags + properties: { + appLogsConfiguration: { + destination: 'log-analytics' + logAnalyticsConfiguration: { + customerId: reference(logAnalyticsWorkspaceResourceId, '2023-09-01').customerId + sharedKey: listKeys(logAnalyticsWorkspaceResourceId, '2023-09-01').primarySharedKey + } + } + vnetConfiguration: empty(infrastructureSubnetId) ? null : { + infrastructureSubnetId: infrastructureSubnetId + } + zoneRedundant: zoneRedundant + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the Container Apps Environment.') +output name string = containerAppEnvironment.name + +@description('The resource ID of the Container Apps Environment.') +output resourceId string = containerAppEnvironment.id + +@description('The default domain of the Container Apps Environment.') +output defaultDomain string = containerAppEnvironment.properties.defaultDomain + +@description('The static IP address of the Container Apps Environment.') +output staticIp string = containerAppEnvironment.properties.staticIp diff --git a/infra/bicep/modules/compute/container-app.bicep b/infra/bicep/modules/compute/container-app.bicep new file mode 100644 index 00000000..15596c7d --- /dev/null +++ b/infra/bicep/modules/compute/container-app.bicep @@ -0,0 +1,117 @@ +// ============================================================================ +// Module: Azure Container App +// Description: Creates an Azure Container App +// API: Microsoft.App/containerApps@2024-10-02-preview +// ============================================================================ + +@description('Name of the container app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Container Apps Environment.') +param environmentResourceId string + +@description('Container definitions.') +param containers array + +@description('Enable external ingress.') +param ingressExternal bool = true + +@description('Target port for ingress.') +param ingressTargetPort int = 80 + +@description('Ingress transport protocol.') +@allowed(['auto', 'http', 'http2', 'tcp']) +param ingressTransport string = 'auto' + +@description('Whether to allow insecure ingress connections.') +param ingressAllowInsecure bool = false + +@description('Disable ingress entirely (for background workers).') +param disableIngress bool = false + +@description('Container registry configurations.') +param registries array? + +@description('Secret definitions.') +param secrets array? + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('CORS policy configuration.') +param corsPolicy object = {} + +@description('Active revision mode.') +@allowed(['Single', 'Multiple']) +param activeRevisionsMode string = 'Single' + +@description('Scale settings (maxReplicas, minReplicas, rules).') +param scaleSettings object = { + maxReplicas: 10 + minReplicas: 0 +} + +@description('Workload profile name.') +param workloadProfileName string? + +// ============================================================================ +// Resource Deployment +// ============================================================================ +var identityConfig = empty(managedIdentities) ? { type: 'None' } : { + type: contains(managedIdentities, 'userAssignedResourceIds') ? (contains(managedIdentities, 'systemAssigned') && managedIdentities.systemAssigned ? 'SystemAssigned,UserAssigned' : 'UserAssigned') : 'SystemAssigned' + userAssignedIdentities: contains(managedIdentities, 'userAssignedResourceIds') ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, id) => union(cur, { '${id}': {} })) : null +} + +var ingressConfig = disableIngress ? null : { + external: ingressExternal + targetPort: ingressTargetPort + transport: ingressTransport + allowInsecure: ingressAllowInsecure + corsPolicy: !empty(corsPolicy) ? corsPolicy : null +} + +resource containerApp 'Microsoft.App/containerApps@2024-10-02-preview' = { + name: name + location: location + tags: tags + identity: identityConfig + properties: { + managedEnvironmentId: environmentResourceId + workloadProfileName: workloadProfileName + configuration: { + activeRevisionsMode: activeRevisionsMode + ingress: ingressConfig + registries: registries + secrets: secrets + } + template: { + containers: containers + scale: { + minReplicas: scaleSettings.minReplicas + maxReplicas: scaleSettings.maxReplicas + rules: contains(scaleSettings, 'rules') ? scaleSettings.rules : null + } + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container app.') +output name string = containerApp.name + +@description('The resource ID of the container app.') +output resourceId string = containerApp.id + +@description('The FQDN of the container app.') +output fqdn string = !disableIngress ? containerApp.properties.configuration.ingress.fqdn : '' + +@description('System-assigned identity principal ID.') +output principalId string = contains(containerApp.identity.type, 'SystemAssigned') ? containerApp.identity.principalId : '' diff --git a/infra/bicep/modules/compute/container-instance.bicep b/infra/bicep/modules/compute/container-instance.bicep new file mode 100644 index 00000000..e3d690ff --- /dev/null +++ b/infra/bicep/modules/compute/container-instance.bicep @@ -0,0 +1,119 @@ +// ============================================================================ +// Module: Azure Container Instance +// Description: Creates an Azure Container Instance group +// API: Microsoft.ContainerInstance/containerGroups@2025-09-01 +// ============================================================================ + +@description('Name of the container group.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Container image to deploy.') +param containerImage string + +@description('CPU cores for the container.') +param cpu int = 2 + +@description('Memory in GB for the container.') +param memoryInGB int = 4 + +@description('Port to expose.') +param port int = 8000 + +@description('Environment variables for the container.') +param environmentVariables array = [] + +@description('Operating system type.') +@allowed(['Linux', 'Windows']) +param osType string = 'Linux' + +@description('Restart policy.') +@allowed(['Always', 'OnFailure', 'Never']) +param restartPolicy string = 'Always' + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Image registry credentials.') +param imageRegistryCredentials array = [] + +@description('Subnet resource ID for VNet integration. If empty, public IP is used.') +param subnetResourceId string = '' + +@description('Availability zone for the container group. Use -1 for no zone.') +param availabilityZone int = -1 + +// ============================================================================ +// Variables +// ============================================================================ +var isPrivateNetworking = !empty(subnetResourceId) + +var identityConfig = empty(managedIdentities) ? { type: 'None' } : { + type: contains(managedIdentities, 'userAssignedResourceIds') ? 'UserAssigned' : 'SystemAssigned' + userAssignedIdentities: contains(managedIdentities, 'userAssignedResourceIds') ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, id) => union(cur, { '${id}': {} })) : null +} + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource containerGroup 'Microsoft.ContainerInstance/containerGroups@2025-09-01' = { + name: name + location: location + tags: tags + identity: identityConfig + zones: availabilityZone != -1 ? [string(availabilityZone)] : null + properties: { + osType: osType + restartPolicy: restartPolicy + containers: [ + { + name: name + properties: { + image: containerImage + resources: { + requests: { + cpu: cpu + memoryInGB: memoryInGB + } + } + ports: [ + { + port: port + protocol: 'TCP' + } + ] + environmentVariables: environmentVariables + } + } + ] + imageRegistryCredentials: imageRegistryCredentials + subnetIds: isPrivateNetworking ? [{ id: subnetResourceId }] : null + ipAddress: { + type: isPrivateNetworking ? 'Private' : 'Public' + ports: [ + { + port: port + protocol: 'TCP' + } + ] + dnsNameLabel: isPrivateNetworking ? null : name + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container group.') +output name string = containerGroup.name + +@description('The resource ID of the container group.') +output resourceId string = containerGroup.id + +@description('The IP address of the container group.') +output ipAddress string = containerGroup.properties.ipAddress.ip diff --git a/infra/bicep/modules/compute/container-registry.bicep b/infra/bicep/modules/compute/container-registry.bicep new file mode 100644 index 00000000..9566d218 --- /dev/null +++ b/infra/bicep/modules/compute/container-registry.bicep @@ -0,0 +1,75 @@ +// ============================================================================ +// Module: Azure Container Registry +// Description: Creates an Azure Container Registry +// API: Microsoft.ContainerRegistry/registries@2025-04-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the container registry.') +param name string = replace('cr${solutionName}', '-', '') + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the container registry.') +@allowed(['Basic', 'Standard', 'Premium']) +param sku string = 'Premium' + +@description('Enable admin user.') +param adminUserEnabled bool = false + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Export policy status.') +param exportPolicyStatus string = 'enabled' + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2025-04-01' = { + name: name + location: location + tags: tags + sku: { + name: sku + } + properties: { + adminUserEnabled: adminUserEnabled + publicNetworkAccess: publicNetworkAccess + dataEndpointEnabled: false + networkRuleBypassOptions: 'AzureServices' + policies: { + exportPolicy: { + status: exportPolicyStatus + } + retentionPolicy: { + status: 'enabled' + days: 7 + } + trustPolicy: { + status: 'disabled' + type: 'Notary' + } + } + zoneRedundancy: 'Disabled' + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container registry.') +output name string = containerRegistry.name + +@description('The login server URL.') +output loginServer string = containerRegistry.properties.loginServer + +@description('The resource ID of the container registry.') +output resourceId string = containerRegistry.id \ No newline at end of file diff --git a/infra/bicep/modules/compute/function-app.bicep b/infra/bicep/modules/compute/function-app.bicep new file mode 100644 index 00000000..4756b20f --- /dev/null +++ b/infra/bicep/modules/compute/function-app.bicep @@ -0,0 +1,100 @@ +// ============================================================================ +// Module: Azure Function App +// Description: Creates an Azure Function App on Linux +// API: Microsoft.Web/sites@2024-04-01 +// ============================================================================ + +@description('Name of the function app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Resource ID of the storage account for function app.') +param storageAccountResourceId string + +@description('Name of the storage account.') +param storageAccountName string + +@description('Managed identity configuration.') +param managedIdentities object = { + systemAssigned: true +} + +@description('App settings as name-value pairs.') +param appSettings array = [] + +@description('Site configuration object.') +param siteConfig object = {} + +@description('Runtime stack.') +param runtimeStack string = 'python' + +@description('Runtime version.') +param runtimeVersion string = '3.11' + +// ============================================================================ +// Variables +// ============================================================================ +var identityConfig = empty(managedIdentities) ? null : { + type: contains(managedIdentities, 'userAssignedResourceIds') ? (contains(managedIdentities, 'systemAssigned') && managedIdentities.systemAssigned ? 'SystemAssigned,UserAssigned' : 'UserAssigned') : 'SystemAssigned' + userAssignedIdentities: contains(managedIdentities, 'userAssignedResourceIds') ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, id) => union(cur, { '${id}': {} })) : null +} + +var storageConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};AccountKey=${listKeys(storageAccountResourceId, '2023-05-01').keys[0].value};EndpointSuffix=${environment().suffixes.storage}' +var linuxFxVersion = '${toUpper(runtimeStack)}|${runtimeVersion}' + +var baseSettings = [ + { name: 'AzureWebJobsStorage', value: storageConnectionString } + { name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' } + { name: 'FUNCTIONS_WORKER_RUNTIME', value: toLower(runtimeStack) } + { name: 'WEBSITE_RUN_FROM_PACKAGE', value: '1' } +] + +var mergedSettings = concat(baseSettings, appSettings) + +var defaultSiteConfig = { + linuxFxVersion: linuxFxVersion + ftpsState: 'Disabled' + minTlsVersion: '1.2' + appSettings: mergedSettings +} + +var effectiveSiteConfig = union(defaultSiteConfig, siteConfig) + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource functionApp 'Microsoft.Web/sites@2024-04-01' = { + name: name + location: location + tags: tags + kind: 'functionapp,linux' + identity: identityConfig + properties: { + serverFarmId: serverFarmResourceId + siteConfig: effectiveSiteConfig + httpsOnly: true + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the function app.') +output name string = functionApp.name + +@description('The resource ID of the function app.') +output resourceId string = functionApp.id + +@description('The default hostname of the function app.') +output defaultHostName string = functionApp.properties.defaultHostName + +@description('The principal ID of the system-assigned managed identity.') +output principalId string = contains(functionApp.identity, 'principalId') ? functionApp.identity.principalId : '' diff --git a/infra/bicep/modules/compute/kubernetes.bicep b/infra/bicep/modules/compute/kubernetes.bicep new file mode 100644 index 00000000..a12df945 --- /dev/null +++ b/infra/bicep/modules/compute/kubernetes.bicep @@ -0,0 +1,134 @@ +// ============================================================================ +// Module: Azure Kubernetes Service (AKS) +// Description: Deploys Azure Kubernetes Service Managed Cluster +// API: Microsoft.ContainerService/managedClusters@2025-03-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the AKS cluster.') +param name string = 'aks-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Kubernetes version for the cluster.') +param kubernetesVersion string = '1.34' + +@description('Agent pool configurations. Each entry requires name, vmSize, count, mode (System/User).') +param agentPools array = [ + { + name: 'systempool' + vmSize: 'Standard_D4ds_v5' + count: 2 + minCount: 1 + maxCount: 3 + enableAutoScaling: true + osType: 'Linux' + mode: 'System' + } +] + +@description('Enable Kubernetes RBAC.') +param enableRBAC bool = true + +@description('Disable local accounts (enforce AAD-only).') +param disableLocalAccounts bool = false + +@description('Network plugin for the cluster.') +@allowed(['azure', 'kubenet', 'none']) +param networkPlugin string = 'azure' + +@description('Network policy for the cluster.') +@allowed(['azure', 'calico', '']) +param networkPolicy string = 'azure' + +@description('DNS prefix for the cluster.') +param dnsPrefix string = '' + +@description('SKU tier for the cluster.') +@allowed(['Free', 'Standard', 'Premium']) +param skuTier string = 'Standard' + +@description('Service CIDR for Kubernetes services.') +param serviceCidr string = '10.20.0.0/16' + +@description('DNS service IP (must be within serviceCidr).') +param dnsServiceIP string = '10.20.0.10' + +@description('Auto-upgrade channel for the cluster.') +@allowed(['none', 'patch', 'rapid', 'stable', 'node-image']) +param autoUpgradeChannel string = 'stable' + +@description('Log Analytics workspace resource ID for monitoring.') +param logAnalyticsWorkspaceResourceId string = '' + +// ============================================================================ +// Variables +// ============================================================================ +var effectiveDnsPrefix = !empty(dnsPrefix) ? dnsPrefix : name + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource aksCluster 'Microsoft.ContainerService/managedClusters@2025-03-01' = { + name: name + location: location + tags: tags + identity: { + type: 'SystemAssigned' + } + sku: { + name: 'Base' + tier: skuTier + } + properties: { + kubernetesVersion: kubernetesVersion + dnsPrefix: effectiveDnsPrefix + enableRBAC: enableRBAC + disableLocalAccounts: disableLocalAccounts + agentPoolProfiles: [for pool in agentPools: { + name: pool.name + vmSize: pool.vmSize + count: pool.count + minCount: pool.?enableAutoScaling == true ? pool.?minCount : null + maxCount: pool.?enableAutoScaling == true ? pool.?maxCount : null + enableAutoScaling: pool.?enableAutoScaling ?? false + osType: pool.?osType ?? 'Linux' + mode: pool.mode + }] + networkProfile: { + networkPlugin: networkPlugin + networkPolicy: !empty(networkPolicy) ? networkPolicy : null + serviceCidr: serviceCidr + dnsServiceIP: dnsServiceIP + } + autoUpgradeProfile: { + upgradeChannel: autoUpgradeChannel + } + addonProfiles: !empty(logAnalyticsWorkspaceResourceId) ? { + omsagent: { + enabled: true + config: { + logAnalyticsWorkspaceResourceID: logAnalyticsWorkspaceResourceId + } + } + } : {} + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AKS cluster.') +output name string = aksCluster.name + +@description('Resource ID of the AKS cluster.') +output resourceId string = aksCluster.id + +@description('FQDN of the AKS cluster.') +output fqdn string = aksCluster.properties.fqdn diff --git a/infra/bicep/modules/data/app-configuration.bicep b/infra/bicep/modules/data/app-configuration.bicep new file mode 100644 index 00000000..6df7aea1 --- /dev/null +++ b/infra/bicep/modules/data/app-configuration.bicep @@ -0,0 +1,63 @@ +// ============================================================================ +// Module: Azure App Configuration +// Description: Creates an Azure App Configuration store +// API: Microsoft.AppConfiguration/configurationStores@2023-03-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the App Configuration store.') +param name string = 'appcs-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU for the configuration store.') +@allowed(['Free', 'Standard']) +param sku string = 'Standard' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Key-value pairs to store in the configuration.') +param keyValues array = [] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = { + name: name + location: location + tags: tags + sku: { + name: sku + } + properties: { + disableLocalAuth: disableLocalAuth + publicNetworkAccess: 'Enabled' + } +} + +resource configurationKeyValues 'Microsoft.AppConfiguration/configurationStores/keyValues@2023-03-01' = [for keyValue in keyValues: { + name: keyValue.name + parent: appConfiguration + properties: { + value: keyValue.value + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the App Configuration store.') +output name string = appConfiguration.name + +@description('The endpoint of the App Configuration store.') +output endpoint string = appConfiguration.properties.endpoint + +@description('The resource ID of the App Configuration store.') +output resourceId string = appConfiguration.id diff --git a/infra/bicep/modules/data/cosmos-db-mongo.bicep b/infra/bicep/modules/data/cosmos-db-mongo.bicep new file mode 100644 index 00000000..620c2f63 --- /dev/null +++ b/infra/bicep/modules/data/cosmos-db-mongo.bicep @@ -0,0 +1,114 @@ +// ============================================================================ +// Module: Cosmos DB (MongoDB) +// Description: Creates an Azure Cosmos DB account with MongoDB API +// API: Microsoft.DocumentDB/databaseAccounts@2025-10-15 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('MongoDB database name.') +param databaseName string = 'default' + +@description('MongoDB collections to create.') +param collections array = [] + +@description('MongoDB server version.') +@allowed(['4.2', '5.0', '6.0', '7.0']) +param serverVersion string = '7.0' + +@description('Default consistency level.') +@allowed(['Eventual', 'ConsistentPrefix', 'Session', 'BoundedStaleness', 'Strong']) +param consistencyLevel string = 'Session' + +@description('Enable analytical storage (Synapse Link).') +param enableAnalyticalStorage bool = false + +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable automatic failover.') +param enableAutomaticFailover bool = false + +@description('HA paired region for multi-region failover.') +param haLocation string = '' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' = { + name: name + location: location + tags: tags + kind: 'MongoDB' + properties: { + consistencyPolicy: { defaultConsistencyLevel: consistencyLevel } + locations: zoneRedundant && !empty(haLocation) + ? [ + { locationName: location, failoverPriority: 0, isZoneRedundant: true } + { locationName: haLocation, failoverPriority: 1, isZoneRedundant: true } + ] + : [ + { locationName: location, failoverPriority: 0, isZoneRedundant: zoneRedundant } + ] + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: enableAutomaticFailover + enableMultipleWriteLocations: false + apiProperties: { serverVersion: serverVersion } + enableAnalyticalStorage: enableAnalyticalStorage + capabilities: [{ name: 'EnableMongo' }] + publicNetworkAccess: publicNetworkAccess + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-10-15' = { + parent: cosmos + name: databaseName + properties: { + resource: { id: databaseName } + } +} + +resource mongoCollections 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-10-15' = [for collection in collections: { + parent: database + name: collection.name + properties: { + resource: { + id: collection.name + shardKey: collection.?shardKey ?? {} + indexes: collection.?indexes ?? [ + { key: { keys: ['_id'] } } + ] + } + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmos.id + +@description('Name of the Cosmos DB account.') +output name string = cosmos.name + +@description('MongoDB connection string (without credentials — use Key Vault for secrets).') +output connectionString string = 'mongodb+srv://${name}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000' + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.mongo.cosmos.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName diff --git a/infra/bicep/modules/data/cosmos-db-nosql.bicep b/infra/bicep/modules/data/cosmos-db-nosql.bicep new file mode 100644 index 00000000..9c758c2e --- /dev/null +++ b/infra/bicep/modules/data/cosmos-db-nosql.bicep @@ -0,0 +1,90 @@ +// ============================================================================ +// Module: Cosmos DB +// Description: Creates an Azure Cosmos DB (NoSQL) account with database/container +// API: Microsoft.DocumentDB/databaseAccounts@2025-10-15 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Database name.') +param databaseName string = 'db_conversation_history' + +@description('Container definitions.') +param containers array = [ + { + name: 'conversations' + partitionKeyPath: '/userId' + } +] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' = { + name: name + location: location + tags: tags + kind: 'GlobalDocumentDB' + properties: { + consistencyPolicy: { defaultConsistencyLevel: 'Session' } + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + enableMultipleWriteLocations: false + disableLocalAuth: true + capabilities: [ { name: 'EnableServerless' } ] + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-10-15' = { + parent: cosmos + name: databaseName + properties: { + resource: { id: databaseName } + } + + resource list 'containers' = [for container in containers: { + name: container.name + properties: { + resource: { + id: container.name + partitionKey: { paths: [ container.partitionKeyPath ] } + } + options: {} + } + }] +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmos.id + +@description('Name of the Cosmos DB account.') +output name string = cosmos.name + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.documents.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName + +@description('Container name (first container).') +output containerName string = containers[0].name diff --git a/infra/bicep/modules/data/event-grid.bicep b/infra/bicep/modules/data/event-grid.bicep new file mode 100644 index 00000000..724481e1 --- /dev/null +++ b/infra/bicep/modules/data/event-grid.bicep @@ -0,0 +1,81 @@ +// ============================================================================ +// Module: Azure Event Grid System Topic +// Description: Deploys Azure Event Grid System Topic +// API: Microsoft.EventGrid/systemTopics@2025-07-15-preview +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Event Grid System Topic.') +param name string = 'evgt-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the source that publishes events (e.g., Storage Account resource ID).') +param source string + +@description('The type of the event source. E.g., Microsoft.Storage.StorageAccounts.') +param topicType string + +@description('Event subscriptions to create on the system topic.') +param eventSubscriptions array = [] + +@description('Managed identities configuration. E.g., { systemAssigned: false, userAssignedResourceIds: [] }.') +param managedIdentities object = {} + +// ============================================================================ +// Resource +// ============================================================================ +resource eventGridSystemTopic 'Microsoft.EventGrid/systemTopics@2025-07-15-preview' = { + name: name + location: location + tags: tags + identity: !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) && !empty(managedIdentities.?userAssignedResourceIds ?? []) + ? 'SystemAssigned,UserAssigned' + : (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : 'UserAssigned' + userAssignedIdentities: !empty(managedIdentities.?userAssignedResourceIds ?? []) + ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, next) => union(cur, { '${next}': {} })) + : null + } : null + properties: { + source: source + topicType: topicType + } +} + +// ============================================================================ +// Event Subscriptions +// ============================================================================ +resource systemTopicSubscriptions 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2025-07-15-preview' = [ + for sub in eventSubscriptions: { + name: sub.name + parent: eventGridSystemTopic + properties: { + destination: sub.destination + filter: sub.?filter ?? {} + eventDeliverySchema: sub.?eventDeliverySchema ?? 'EventGridSchema' + retryPolicy: sub.?retryPolicy ?? { + maxDeliveryAttempts: 30 + eventTimeToLiveInMinutes: 1440 + } + } + } +] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the Event Grid System Topic.') +output name string = eventGridSystemTopic.name + +@description('Resource ID of the Event Grid System Topic.') +output resourceId string = eventGridSystemTopic.id + +@description('System-assigned principal ID (if enabled).') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) ? eventGridSystemTopic.identity.principalId : '' diff --git a/infra/bicep/modules/data/event-hub.bicep b/infra/bicep/modules/data/event-hub.bicep new file mode 100644 index 00000000..1dfb8a89 --- /dev/null +++ b/infra/bicep/modules/data/event-hub.bicep @@ -0,0 +1,62 @@ +// ============================================================================ +// Module: Azure Event Hub Namespace +// Description: Creates an Azure Event Hub Namespace with event hubs +// API: Microsoft.EventHub/namespaces@2024-01-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Event Hub namespace.') +param name string = 'evhns-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('The SKU tier for the Event Hub namespace.') +param sku string = 'Standard' + +@description('The throughput unit or processing unit capacity.') +param capacity int = 1 + +@description('Event hubs to create within the namespace.') +param eventhubs array = [] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource eventHubNamespace 'Microsoft.EventHub/namespaces@2024-01-01' = { + name: name + location: location + tags: tags + sku: { + name: sku + tier: sku + capacity: capacity + } + properties: { + minimumTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + } +} + +resource eventHubResources 'Microsoft.EventHub/namespaces/eventhubs@2024-01-01' = [for eventhub in eventhubs: { + name: eventhub.name + parent: eventHubNamespace + properties: { + messageRetentionInDays: eventhub.?messageRetentionInDays ?? 1 + partitionCount: eventhub.?partitionCount ?? 2 + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the Event Hub namespace.') +output name string = eventHubNamespace.name + +@description('The resource ID of the Event Hub namespace.') +output resourceId string = eventHubNamespace.id diff --git a/infra/bicep/modules/data/postgresql-flexible-server.bicep b/infra/bicep/modules/data/postgresql-flexible-server.bicep new file mode 100644 index 00000000..3c6cb0eb --- /dev/null +++ b/infra/bicep/modules/data/postgresql-flexible-server.bicep @@ -0,0 +1,133 @@ +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the PostgreSQL Flexible Server.') +param name string = 'psql-${solutionName}' + +@description('The Azure region where the PostgreSQL Flexible Server will be deployed.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Azure AD administrators for the server. Each entry requires objectId, principalName, and principalType (User, Group, or ServicePrincipal).') +param administrators array + +@description('The PostgreSQL version to deploy.') +param version string = '16' + +@description('The SKU name for the PostgreSQL Flexible Server.') +param skuName string = 'Standard_B1ms' + +@description('The SKU tier for the PostgreSQL Flexible Server.') +@allowed(['Burstable', 'GeneralPurpose', 'MemoryOptimized']) +param skuTier string = 'Burstable' + +@description('The storage size in GB.') +param storageSizeGB int = 32 + +@description('Optional databases to create on the server. Each entry should have a name, and optionally charset and collation.') +param databases array = [] + +@description('Optional server configurations (e.g., extensions). Each entry should have a name, value, and source.') +param configurations array = [] + +resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2026-01-01-preview' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: skuTier + } + properties: { + version: version + storage: { + storageSizeGB: storageSizeGB + } + authConfig: { + activeDirectoryAuth: 'Enabled' + passwordAuth: 'Disabled' + } + highAvailability: { + mode: 'Disabled' + } + network: { + publicNetworkAccess: 'Enabled' + } + } +} + +resource firewallAllowAzureIPs 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2026-01-01-preview' = { + name: 'AllowAllAzureServicesAndResourcesWithinAzureIps' + parent: postgresServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } +} + +resource firewallAllowAll 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2026-01-01-preview' = { + name: 'AllowAll' + parent: postgresServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } +} + +// AAD admins must wait for firewall rules — server needs to be fully accessible first +@batchSize(1) +resource postgresAdmins 'Microsoft.DBforPostgreSQL/flexibleServers/administrators@2026-01-01-preview' = [ + for admin in administrators: { + parent: postgresServer + name: admin.objectId + dependsOn: [ + firewallAllowAzureIPs + firewallAllowAll + ] + properties: { + principalName: admin.principalName + principalType: admin.principalType + tenantId: subscription().tenantId + } + } +] + +resource serverDatabases 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2026-01-01-preview' = [ + for db in databases: { + name: db.name + parent: postgresServer + properties: { + charset: db.?charset ?? 'UTF8' + collation: db.?collation ?? 'en_US.utf8' + } + dependsOn: [ + postgresAdmins + ] + } +] + +@batchSize(1) +resource serverConfigurations 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2026-01-01-preview' = [ + for config in configurations: { + name: config.name + parent: postgresServer + properties: { + value: config.value + source: config.source + } + dependsOn: [ + postgresAdmins + ] + } +] + +@description('The fully qualified domain name of the PostgreSQL Flexible Server.') +output serverFqdn string = postgresServer.properties.fullyQualifiedDomainName + +@description('The name of the PostgreSQL Flexible Server.') +output name string = postgresServer.name + +@description('The resource ID of the PostgreSQL Flexible Server.') +output resourceId string = postgresServer.id diff --git a/infra/bicep/modules/data/sql-database.bicep b/infra/bicep/modules/data/sql-database.bicep new file mode 100644 index 00000000..2e647c1e --- /dev/null +++ b/infra/bicep/modules/data/sql-database.bicep @@ -0,0 +1,115 @@ +// ============================================================================ +// Module: SQL Database +// Description: Creates an Azure SQL Server and Database +// API: Microsoft.Sql/servers@2025-01-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the SQL Server.') +param name string = 'sql-${solutionName}' + +@description('Name of the SQL Database.') +param databaseName string = 'sqldb-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Principal ID of the deployer for admin access.') +param deployerPrincipalId string + +@description('SKU name for the database.') +param skuName string = 'GP_S_Gen5' + +@description('SKU tier for the database.') +param skuTier string = 'GeneralPurpose' + +@description('SKU family.') +param skuFamily string = 'Gen5' + +@description('vCore capacity.') +param skuCapacity int = 2 + +@description('Auto-pause delay in minutes.') +param autoPauseDelay int = 60 + +@description('Minimum capacity (vCores).') +param minCapacity int = 1 + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource sqlServer 'Microsoft.Sql/servers@2025-01-01' = { + name: name + location: location + tags: tags + properties: { + publicNetworkAccess: 'Enabled' + version: '12.0' + restrictOutboundNetworkAccess: 'Disabled' + minimalTlsVersion: '1.2' + administrators: { + login: deployerPrincipalId + sid: deployerPrincipalId + tenantId: subscription().tenantId + administratorType: 'ActiveDirectory' + azureADOnlyAuthentication: true + } + } +} + +resource firewallRule 'Microsoft.Sql/servers/firewallRules@2025-01-01' = { + name: 'AllowSpecificRange' + parent: sqlServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } +} + +resource AllowAllWindowsAzureIps 'Microsoft.Sql/servers/firewallRules@2025-01-01' = { + name: 'AllowAllWindowsAzureIps' + parent: sqlServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } +} + +resource sqlDB 'Microsoft.Sql/servers/databases@2025-01-01' = { + parent: sqlServer + name: databaseName + location: location + sku: { + name: skuName + tier: skuTier + family: skuFamily + capacity: skuCapacity + } + properties: { + collation: 'SQL_Latin1_General_CP1_CI_AS' + autoPauseDelay: autoPauseDelay + minCapacity: minCapacity + readScale: 'Disabled' + zoneRedundant: false + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Fully qualified domain name of the SQL Server.') +output serverFqdn string = '${name}.database.windows.net' + +@description('Name of the SQL Database.') +output databaseName string = databaseName + +@description('Resource ID of the SQL Server.') +output serverResourceId string = sqlServer.id + +@description('Name of the SQL Server.') +output name string = sqlServer.name diff --git a/infra/bicep/modules/data/storage-account.bicep b/infra/bicep/modules/data/storage-account.bicep new file mode 100644 index 00000000..ea9d5386 --- /dev/null +++ b/infra/bicep/modules/data/storage-account.bicep @@ -0,0 +1,101 @@ +// ============================================================================ +// Module: Storage Account +// Description: Creates an Azure Storage Account with blob container +// API: Microsoft.Storage/storageAccounts@2025-08-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the storage account.') +param name string = take('st${toLower(replace(solutionName, '-', ''))}', 24) + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Storage account SKU.') +param skuName string = 'Standard_LRS' + +@description('Storage account kind.') +param kind string = 'StorageV2' + +@description('Access tier.') +@allowed(['Hot', 'Cool']) +param accessTier string = 'Hot' + +@description('Allow blob public access.') +param allowBlobPublicAccess bool = false + +@description('Allow shared key access.') +param allowSharedKeyAccess bool = true + +@description('Blob containers to create.') +param containers array = [ + { + name: 'default' + publicAccess: 'None' + } +] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' = { + name: name + location: location + tags: tags + kind: kind + sku: { + name: skuName + } + properties: { + accessTier: accessTier + allowBlobPublicAccess: allowBlobPublicAccess + allowSharedKeyAccess: allowSharedKeyAccess + minimumTlsVersion: 'TLS1_2' + supportsHttpsTrafficOnly: true + encryption: { + services: { + blob: { + enabled: true + } + file: { + enabled: true + } + } + keySource: 'Microsoft.Storage' + requireInfrastructureEncryption: true + } + } +} + +resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2025-08-01' = { + parent: storageAccount + name: 'default' +} + +resource blobContainers 'Microsoft.Storage/storageAccounts/blobServices/containers@2025-08-01' = [for container in containers: { + parent: blobService + name: container.name + properties: { + publicAccess: container.publicAccess + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Storage Account.') +output resourceId string = storageAccount.id + +@description('Name of the Storage Account.') +output name string = storageAccount.name + +@description('Primary blob endpoint.') +output blobEndpoint string = storageAccount.properties.primaryEndpoints.blob + +@description('All service endpoints.') +output serviceEndpoints object = storageAccount.properties.primaryEndpoints diff --git a/infra/bicep/modules/fabric/fabric-capacity.bicep b/infra/bicep/modules/fabric/fabric-capacity.bicep new file mode 100644 index 00000000..17f6498b --- /dev/null +++ b/infra/bicep/modules/fabric/fabric-capacity.bicep @@ -0,0 +1,72 @@ +// ============================================================================ +// Module: Fabric Capacity +// Description: Vanilla Bicep module for Microsoft Fabric Capacity +// Resource: Microsoft.Fabric/capacities@2023-11-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.fabric/capacities +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Fabric capacity. Defaults to fc{solutionName}.') +param name string = 'fc${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU tier of the Fabric capacity.') +@allowed([ + 'F2' + 'F4' + 'F8' + 'F16' + 'F32' + 'F64' + 'F128' + 'F256' + 'F512' + 'F1024' + 'F2048' +]) +param skuName string = 'F2' + +@description('List of admin members (UPNs for users, object IDs for service principals).') +param adminMembers array + +// ============================================================================ +// Resource +// ============================================================================ + +resource fabricCapacity 'Microsoft.Fabric/capacities@2023-11-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: 'Fabric' + } + properties: { + administration: { + members: adminMembers + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the deployed Fabric capacity.') +output name string = fabricCapacity.name + +@description('The resource ID of the deployed Fabric capacity.') +output resourceId string = fabricCapacity.id + +@description('The resource group name.') +output resourceGroupName string = resourceGroup().name + +@description('The location of the deployed Fabric capacity.') +output location string = fabricCapacity.location diff --git a/infra/bicep/modules/identity/cross-scope-role-assignment.bicep b/infra/bicep/modules/identity/cross-scope-role-assignment.bicep new file mode 100644 index 00000000..19e43cc0 --- /dev/null +++ b/infra/bicep/modules/identity/cross-scope-role-assignment.bicep @@ -0,0 +1,37 @@ +// ============================================================================ +// cross-scope-role-assignment.bicep +// Description: Reusable helper that creates a single role assignment scoped +// to an existing AI Services resource. Used for cross-resource- +// group RBAC where the AI Services lives in a different RG. +// ============================================================================ + +@description('The principal ID to assign the role to.') +param principalId string + +@description('The resource ID of the role definition to assign.') +param roleDefinitionId string + +@description('A unique name for the role assignment.') +param roleAssignmentName string + +@description('The name of the AI Services account to scope the role assignment to.') +param aiFoundryName string + +@description('The principal type of the identity being assigned.') +@allowed(['ServicePrincipal', 'User']) +param principalType string = 'ServicePrincipal' + +// Reference the existing AI Services resource in this resource group +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiFoundryName +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: roleAssignmentName + scope: aiServices + properties: { + roleDefinitionId: roleDefinitionId + principalId: principalId + principalType: principalType + } +} diff --git a/infra/bicep/modules/identity/managed-identity.bicep b/infra/bicep/modules/identity/managed-identity.bicep new file mode 100644 index 00000000..e8accb80 --- /dev/null +++ b/infra/bicep/modules/identity/managed-identity.bicep @@ -0,0 +1,43 @@ +// ============================================================================ +// Module: User-Assigned Managed Identity (Generic) +// Description: Creates a user-assigned managed identity. +// This module is NOT called from main.bicep by default. +// Use it when you need a user-assigned identity for specific scenarios +// (e.g., Container Apps, cross-tenant access, pre-provisioned RBAC). +// ============================================================================ + +@description('Solution name used for resource naming.') +param solutionName string + +@description('Name of the managed identity.') +param identityName string = 'id-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: identityName + location: location + tags: tags +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the managed identity.') +output resourceId string = managedIdentity.id + +@description('Principal ID (object ID) of the managed identity.') +output principalId string = managedIdentity.properties.principalId + +@description('Client ID of the managed identity.') +output clientId string = managedIdentity.properties.clientId + +@description('Name of the managed identity.') +output name string = managedIdentity.name diff --git a/infra/bicep/modules/identity/role-assignments.bicep b/infra/bicep/modules/identity/role-assignments.bicep new file mode 100644 index 00000000..00559492 --- /dev/null +++ b/infra/bicep/modules/identity/role-assignments.bicep @@ -0,0 +1,350 @@ +// ============================================================================ +// Module: Role Assignments (centralized — all cross-service + data plane RBAC) +// Description: RG-level, cross-service, and data-plane role assignments. +// One place to audit "who has access to what". +// ============================================================================ + +// ============================================================================ +// Parameters +// ============================================================================ + +@description('Solution name suffix for generating unique role assignment GUIDs.') +param solutionName string = '' + +@description('Whether to use an existing AI project (true) or create new (false).') +param useExistingAIProject bool = false + +@description('Resource ID of the existing AI project (for deriving AI Services name/sub/RG).') +param existingFoundryProjectResourceId string = '' + +// --- Identity Principal IDs --- + +@description('Principal ID of the AI project identity.') +param aiProjectPrincipalId string = '' + +@description('Principal ID of the existing AI project identity (for cross-service roles).') +param existingAiProjectPrincipalId string = '' + +@description('Principal ID of the AI Search identity.') +param aiSearchPrincipalId string = '' + +@description('Principal ID of the backend App Service system-assigned identity (empty if not deployed).') +param backendAppServicePrincipalId string = '' + +@description('Principal ID of the deploying user (for user access roles).') +param deployerPrincipalId string = '' + +@description('Principal type of the deploying user.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + +// --- Resource References --- + +@description('Resource ID of the AI Foundry account (empty if not deployed — new project path).') +param aiFoundryResourceId string = '' + +@description('Resource ID of the AI Search service (empty if not deployed).') +param aiSearchResourceId string = '' + +@description('Resource ID of the Storage Account (empty if not deployed).') +param storageAccountResourceId string = '' + +@description('Name of the Cosmos DB account (empty if not deployed).') +param cosmosDbAccountName string = '' + +// ============================================================================ +// Derived Variables +// ============================================================================ + +var existingAIFoundryName = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[8] : '' +var existingAIFoundrySubscription = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[2] : subscription().subscriptionId +var existingAIFoundryResourceGroup = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[4] : resourceGroup().name + +// ============================================================================ +// Role Definitions +// ============================================================================ + +var roleDefinitions = { + azureAiUser: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Foundry User + cognitiveServicesUser: 'a97b65f3-24c7-4388-baec-2e87135dc908' + cognitiveServicesOpenAIUser: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + searchIndexDataReader: '1407120a-92aa-4202-b7e9-c0e197c71c8f' + searchIndexDataContributor: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' + searchServiceContributor: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' + storageBlobDataContributor: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + storageBlobDataReader: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +} + +// ============================================================================ +// Existing Resource References +// ============================================================================ + +resource aiFoundryAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if (!empty(aiFoundryResourceId)) { + name: last(split(aiFoundryResourceId, '/')) +} + +resource aiSearchService 'Microsoft.Search/searchServices@2025-05-01' existing = if (!empty(aiSearchResourceId)) { + name: last(split(aiSearchResourceId, '/')) +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' existing = if (!empty(storageAccountResourceId)) { + name: last(split(storageAccountResourceId, '/')) +} + +resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + name: cosmosDbAccountName +} + +resource cosmosContributorRoleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + parent: cosmosAccount + name: '00000000-0000-0000-0000-000000000002' // Cosmos DB Built-in Data Contributor +} + +// ============================================================================ +// 1. AI SERVICES ROLE ASSIGNMENTS +// Cross-service roles scoped to AI Foundry account +// ============================================================================ + +// AI Search → Cognitive Services OpenAI User on AI Foundry (new project, same RG) +resource assignOpenAIRoleToAISearch 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiSearchPrincipalId) && !empty(aiFoundryResourceId)) { + name: guid(aiFoundryAccount.id, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + scope: aiFoundryAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Cognitive Services OpenAI User on existing AI Foundry (cross-scope) +module assignOpenAIToSearchExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(aiSearchPrincipalId)) { + name: 'assignOpenAIRoleToAISearchExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + roleAssignmentName: guid(existingAIFoundryName, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + aiFoundryName: existingAIFoundryName + } +} + +// Backend App Service → Foundry User on AI Foundry (new project, same RG) +resource backendAppAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiFoundryResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiFoundryAccount.id, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + scope: aiFoundryAccount + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Foundry User on existing AI Foundry (cross-scope) +module backendAppAiUserExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(backendAppServicePrincipalId)) { + name: 'assignAiUserRoleToBackendExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + roleAssignmentName: guid(existingAIFoundryName, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + aiFoundryName: existingAIFoundryName + } +} + +// ============================================================================ +// 2. SEARCH SERVICE ROLE ASSIGNMENTS +// AI Project and Backend identities → AI Search +// ============================================================================ + +// AI Project → Search Index Data Reader on AI Search (new project) +resource projectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Search Service Contributor on AI Search (new project) +resource projectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Index Data Reader on AI Search +resource existingProjectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Service Contributor on AI Search +resource existingProjectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Search Index Data Reader on AI Search +resource backendAppSearchReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiSearchService.id, backendAppServicePrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 3. STORAGE ROLE ASSIGNMENTS +// AI Project, AI Search, and Existing Project identities → Storage +// ============================================================================ + +// AI Project → Storage Blob Data Contributor (new project) +resource projectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Storage Blob Data Reader (new project) +resource projectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Contributor +resource existingProjectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Reader +resource existingProjectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Storage Blob Data Reader +resource searchStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiSearchPrincipalId)) { + name: guid(storageAccount.id, aiSearchPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 4. COSMOS DB ROLE ASSIGNMENTS +// Backend App Service → Cosmos DB (data-plane, uses sqlRoleAssignments) +// ============================================================================ + +resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) { + parent: cosmosAccount + name: guid(cosmosContributorRoleDefinition.id, cosmosAccount.id, backendAppServicePrincipalId) + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: cosmosContributorRoleDefinition.id + scope: cosmosAccount.id + } +} + +// ============================================================================ +// 5. DEPLOYER (USER) ROLE ASSIGNMENTS +// Deploying user → AI Services, Search, Storage (Bicep-only) +// ============================================================================ + +// Deploying User → Cognitive Services User on AI Services +resource deployerAiServicesAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(deployerPrincipalId) && !empty(aiFoundryResourceId)) { + scope: aiFoundryAccount + name: guid(aiFoundryAccount.id, deployerPrincipalId, roleDefinitions.cognitiveServicesUser) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesUser) + principalType: deployerPrincipalType + } +} + +// Deploying User → Foundry User on AI Services +resource deployerAzureAIAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(deployerPrincipalId) && !empty(aiFoundryResourceId)) { + scope: aiFoundryAccount + name: guid(aiFoundryAccount.id, deployerPrincipalId, roleDefinitions.azureAiUser) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + principalType: deployerPrincipalType + } +} + +// Deploying User → Search Index Data Contributor on AI Search +resource deployerSearchIndexContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(aiSearchResourceId)) { + scope: aiSearchService + name: guid(aiSearchService.id, deployerPrincipalId, roleDefinitions.searchIndexDataContributor) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataContributor) + principalType: deployerPrincipalType + } +} + +// Deploying User → Search Service Contributor on AI Search +resource deployerSearchServiceContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(aiSearchResourceId)) { + scope: aiSearchService + name: guid(aiSearchService.id, deployerPrincipalId, roleDefinitions.searchServiceContributor) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: deployerPrincipalType + } +} + +// Deploying User → Storage Blob Data Contributor +resource deployerStorageBlobContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(storageAccountResourceId)) { + scope: storageAccount + name: guid(storageAccount.id, deployerPrincipalId, roleDefinitions.storageBlobDataContributor) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: deployerPrincipalType + } +} + +// NOTE: Deployer roles on existing AI Foundry (cross-scope) are assigned via +// 00_build_solution.py to avoid conflicts when the deployer already has the roles. diff --git a/infra/bicep/modules/monitoring/app-insights.bicep b/infra/bicep/modules/monitoring/app-insights.bicep new file mode 100644 index 00000000..f3ebe34b --- /dev/null +++ b/infra/bicep/modules/monitoring/app-insights.bicep @@ -0,0 +1,72 @@ +// ============================================================================ +// Module: Application Insights +// Description: Vanilla Bicep module for Application Insights +// Resource: Microsoft.Insights/components@2020-02-02 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.insights/components +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}.') +param name string = 'appi-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace to link to.') +param workspaceResourceId string + +@description('Application type.') +param applicationType string = 'web' + +@description('Retention period in days.') +param retentionInDays int = 365 + +@description('Disable IP masking for security.') +param disableIpMasking bool = false + +@description('Flow type for Application Insights.') +param flowType string = 'Bluefield' + +// ============================================================================ +// Resource +// ============================================================================ + +resource appInsights 'Microsoft.Insights/components@2020-02-02' = { + name: name + location: location + tags: tags + kind: 'web' + properties: { + Application_Type: applicationType + Flow_Type: flowType + WorkspaceResourceId: workspaceResourceId + RetentionInDays: retentionInDays + DisableIpMasking: disableIpMasking + publicNetworkAccessForIngestion: 'Enabled' + publicNetworkAccessForQuery: 'Enabled' + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the Application Insights instance.') +output resourceId string = appInsights.id + +@description('Name of the Application Insights instance.') +output name string = appInsights.name + +@description('Instrumentation key for the Application Insights instance.') +output instrumentationKey string = appInsights.properties.InstrumentationKey + +@description('Connection string for the Application Insights instance.') +output connectionString string = appInsights.properties.ConnectionString + +@description('Application ID of the Application Insights instance.') +output applicationId string = appInsights.properties.AppId diff --git a/infra/bicep/modules/monitoring/log-analytics.bicep b/infra/bicep/modules/monitoring/log-analytics.bicep new file mode 100644 index 00000000..87d79740 --- /dev/null +++ b/infra/bicep/modules/monitoring/log-analytics.bicep @@ -0,0 +1,58 @@ +// ============================================================================ +// Module: Log Analytics Workspace +// Description: Vanilla Bicep module for Log Analytics Workspace +// Resource: Microsoft.OperationalInsights/workspaces@2023-09-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.operationalinsights/workspaces +// Note: This module only handles NEW workspace creation. +// Existing workspace logic is handled in main.bicep. +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}.') +param name string = 'log-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Retention period in days.') +param retentionInDays int = 365 + +@description('SKU name for the workspace.') +param skuName string = 'PerGB2018' + +// ============================================================================ +// Resource +// ============================================================================ + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: name + location: location + tags: tags + properties: { + retentionInDays: retentionInDays + sku: { + name: skuName + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the Log Analytics workspace.') +output resourceId string = logAnalytics.id + +@description('Name of the Log Analytics workspace.') +output name string = logAnalytics.name + +@description('Location of the workspace.') +output location string = logAnalytics.location + +@description('Log Analytics workspace customer ID.') +output logAnalyticsWorkspaceId string = logAnalytics.properties.customerId diff --git a/infra/bicep/modules/monitoring/portal-dashboard.bicep b/infra/bicep/modules/monitoring/portal-dashboard.bicep new file mode 100644 index 00000000..c5c08ec8 --- /dev/null +++ b/infra/bicep/modules/monitoring/portal-dashboard.bicep @@ -0,0 +1,49 @@ +// ============================================================================ +// Module: Portal Dashboard (Application Insights) +// Description: Vanilla Bicep module for Azure Portal Dashboard +// Resource: Microsoft.Portal/dashboards@2025-04-01-preview +// Docs: https://learn.microsoft.com/azure/templates/microsoft.portal/dashboards +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the dashboard.') +param name string = 'dash-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Lenses (tile groups) to display on the dashboard.') +param lenses array = [] + +@description('Dashboard metadata (time range, filters, etc.).') +param metadata object = {} + +// ============================================================================ +// Resource +// ============================================================================ +resource dashboard 'Microsoft.Portal/dashboards@2025-04-01-preview' = { + name: name + location: location + tags: tags + properties: { + lenses: lenses + metadata: !empty(metadata) ? metadata : {} + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the dashboard.') +output resourceId string = dashboard.id + +@description('Name of the dashboard.') +output name string = dashboard.name + +@description('Resource group the dashboard was deployed to.') +output resourceGroupName string = resourceGroup().name diff --git a/infra/bicep/modules/security/key-vault.bicep b/infra/bicep/modules/security/key-vault.bicep new file mode 100644 index 00000000..acd258db --- /dev/null +++ b/infra/bicep/modules/security/key-vault.bicep @@ -0,0 +1,81 @@ +// ============================================================================ +// Module: Azure Key Vault +// Description: Vanilla Bicep module for Azure Key Vault +// Resource: Microsoft.KeyVault/vaults@2023-07-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.keyvault/vaults +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Optional. Override name for the Key Vault. Defaults to kv-{solutionName}.') +param name string = take('kv-${solutionName}', 24) + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the key vault.') +@allowed(['standard', 'premium']) +param sku string = 'standard' + +@description('Enable RBAC authorization.') +param enableRbacAuthorization bool = true + +@description('Enable soft delete.') +param enableSoftDelete bool = true + +@description('Soft delete retention in days.') +param softDeleteRetentionInDays int = 90 + +@description('Enable purge protection.') +param enablePurgeProtection bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('The Microsoft Entra tenant ID for the Key Vault.') +param tenantId string = subscription().tenantId + +// ============================================================================ +// Key Vault Resource +// ============================================================================ + +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { + name: name + location: location + tags: tags + properties: { + tenantId: tenantId + sku: { + family: 'A' + name: sku + } + accessPolicies: [] + enableRbacAuthorization: enableRbacAuthorization + enableSoftDelete: enableSoftDelete + softDeleteRetentionInDays: softDeleteRetentionInDays + enablePurgeProtection: enablePurgeProtection + publicNetworkAccess: publicNetworkAccess + networkAcls: { + bypass: 'AzureServices' + defaultAction: publicNetworkAccess == 'Disabled' ? 'Deny' : 'Allow' + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the Key Vault.') +output name string = keyVault.name + +@description('The URI of the Key Vault.') +output uri string = keyVault.properties.vaultUri + +@description('The resource ID of the Key Vault.') +output resourceId string = keyVault.id From c66e6bba0a72146d240f7b589ad46b67bcd9f101 Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Wed, 10 Jun 2026 16:36:41 +0530 Subject: [PATCH 2/8] Add .gitkeep files to maintain directory structure for provisioning scripts --- infra/README.md | 91 + infra/avm/main.bicep | 1872 + infra/avm/main.json | 68661 ++++++++ infra/bicep/main.bicep | 794 + infra/bicep/main.json | 3406 + infra/main.bicep | 1935 +- infra/main.json | 121370 ++++++++------- infra/modules/account/aifoundry.bicep | 421 - .../account/modules/dependencies.bicep | 479 - .../account/modules/keyVaultExport.bicep | 43 - infra/modules/account/modules/project.bicep | 62 - infra/modules/container-registry.bicep | 92 - infra/modules/log-analytics-workspace.bicep | 105 - infra/modules/managed-identity.bicep | 25 - infra/modules/virtualNetwork.bicep | 397 - infra/scripts/post-provision/.gitkeep | 0 infra/scripts/pre-provision/.gitkeep | 0 infra/scripts/utilities/.gitkeep | 0 18 files changed, 138642 insertions(+), 61111 deletions(-) create mode 100644 infra/README.md create mode 100644 infra/avm/main.bicep create mode 100644 infra/avm/main.json create mode 100644 infra/bicep/main.bicep create mode 100644 infra/bicep/main.json delete mode 100644 infra/modules/account/aifoundry.bicep delete mode 100644 infra/modules/account/modules/dependencies.bicep delete mode 100644 infra/modules/account/modules/keyVaultExport.bicep delete mode 100644 infra/modules/account/modules/project.bicep delete mode 100644 infra/modules/container-registry.bicep delete mode 100644 infra/modules/log-analytics-workspace.bicep delete mode 100644 infra/modules/managed-identity.bicep delete mode 100644 infra/modules/virtualNetwork.bicep create mode 100644 infra/scripts/post-provision/.gitkeep create mode 100644 infra/scripts/pre-provision/.gitkeep create mode 100644 infra/scripts/utilities/.gitkeep diff --git a/infra/README.md b/infra/README.md new file mode 100644 index 00000000..cf65b97b --- /dev/null +++ b/infra/README.md @@ -0,0 +1,91 @@ +# Infrastructure — Content Processing Solution Accelerator + +This folder contains the Bicep/ARM infrastructure-as-code for the Content Processing Solution Accelerator. + +## Deployment Flavors + +| Flavor | Description | +|--------|-------------| +| `avm` | Azure Verified Modules — production-grade, non-WAF | +| `avm-waf` | AVM with WAF-aligned features (monitoring, private networking, scalability, redundancy) | +| `bicep` | Vanilla Bicep — direct ARM resource definitions | + +## Folder Structure + +``` +infra/ +├── main.bicep ← Deployment router (selects flavor) +├── main.json ← Compiled ARM template (used by CI/CD) +├── main.parameters.json ← Standard deployment parameters +├── main.waf.parameters.json ← WAF deployment parameters +├── main_custom.bicep ← Oryx source-code build variant (azd deploy) +├── avm/ +│ ├── main.bicep ← AVM orchestrator +│ ├── main.json ← Compiled ARM +│ └── modules/ +│ ├── ai/ ← AI Services, AI Search +│ ├── compute/ ← Container Registry +│ ├── identity/ ← Managed Identity +│ ├── monitoring/ ← Log Analytics +│ └── networking/ ← VNet, Bastion, Private DNS +├── bicep/ +│ ├── main.bicep ← Vanilla Bicep orchestrator +│ ├── main.json ← Compiled ARM +│ └── modules/ +│ ├── ai/ ← AI Services, Project, Model, Search +│ ├── compute/ ← Container Apps, Environment, Registry +│ ├── data/ ← Storage, Cosmos DB, App Configuration +│ ├── identity/ ← Managed Identity +│ └── monitoring/ ← Log Analytics, App Insights +├── scripts/ +│ ├── build/ ← Build-time scripts +│ ├── post-provision/ ← Post-provisioning hooks +│ ├── pre-provision/ ← Pre-provisioning hooks +│ └── utilities/ ← Utility scripts +└── azure.yaml ← azd infrastructure config +``` + +## Usage + +### Deploy with Azure Developer CLI (azd) + +```bash +# Standard deployment (AVM flavor) +azd up + +# WAF deployment +azd up --environment-values DEPLOYMENT_FLAVOR=avm-waf +``` + +### Deploy with Azure CLI + +```bash +az deployment group create \ + --resource-group \ + --template-file infra/main.json \ + --parameters infra/main.parameters.json +``` + +### Build ARM template from Bicep + +```bash +az bicep build --file infra/main.bicep --outfile infra/main.json +``` + +## Parameters + +| Parameter | Required | Description | +|-----------|:--------:|-------------| +| `deploymentFlavor` | No | `avm` (default), `bicep`, or `avm-waf` | +| `solutionName` | No | Solution name (3-20 chars), default: `cps` | +| `location` | Yes | Azure region for resources | +| `azureAiServiceLocation` | Yes | Azure region for AI Services | +| `gptModelName` | No | GPT model name, default: `gpt-5.1` | +| `deploymentType` | No | `GlobalStandard` (default) or `Standard` | +| `gptModelVersion` | No | Model version, default: `2025-11-13` | +| `gptDeploymentCapacity` | No | TPM capacity, default: `300` | +| `imageTag` | No | Container image tag, default: `latest_v2` | +| `enablePrivateNetworking` | No | Enable VNet/private endpoints | +| `enableMonitoring` | No | Enable Log Analytics + App Insights | +| `enableRedundancy` | No | Enable zone redundancy | +| `enableScalability` | No | Enable higher scale defaults | diff --git a/infra/avm/main.bicep b/infra/avm/main.bicep new file mode 100644 index 00000000..a492c376 --- /dev/null +++ b/infra/avm/main.bicep @@ -0,0 +1,1872 @@ +// ========== main.bicep ========== // +targetScope = 'resourceGroup' + +metadata name = 'Content Processing Solution Accelerator' +metadata description = 'Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance.' + +// ========== Parameters ========== // +@minLength(3) +@maxLength(20) +@description('Optional. Name of the solution to deploy. This should be 3-20 characters long.') +param solutionName string = 'cps' + +@metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).') +@allowed([ + 'australiaeast' + 'centralus' + 'eastasia' + 'eastus2' + 'japaneast' + 'northeurope' + 'southeastasia' + 'uksouth' +]) +param location string + +@minLength(1) +@allowed([ + 'australiaeast' + 'eastus' + 'eastus2' + 'japaneast' + 'southcentralus' + 'southeastasia' + 'swedencentral' + 'uksouth' + 'westeurope' + 'westus' + 'westus3' +]) +@description('Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead.') +@metadata({ + azd: { + type: 'location' + usageName: [ + 'OpenAI.GlobalStandard.gpt-5.1,300' + ] + } +}) +param azureAiServiceLocation string + +@description('Optional. Type of GPT deployment to use: Standard | GlobalStandard.') +@minLength(1) +@allowed([ + 'Standard' + 'GlobalStandard' +]) +param deploymentType string = 'GlobalStandard' + +@description('Optional. Name of the GPT model to deploy: gpt-5.1') +param gptModelName string = 'gpt-5.1' + +@minLength(1) +@description('Optional. Version of the GPT model to deploy:.') +@allowed([ + '2025-11-13' +]) +param gptModelVersion string = '2025-11-13' + +@minValue(1) +@description('Optional. Capacity of the GPT deployment: (minimum 10).') +param gptDeploymentCapacity int = 300 + +@description('Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint).') +param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' + +@description('Optional. The image tag for the container images.') +param imageTag string = 'latest_v2' + +@description('Optional. Enable WAF for the deployment.') +param enablePrivateNetworking bool = false + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') +param enableMonitoring bool = false + +@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableRedundancy bool = false + +@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableScalability bool = false + +@description('Optional. Enable purge protection. Defaults to false.') +param enablePurgeProtection bool = false + +@description('Optional. Tags to be applied to the resources.') +param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location +} + +@description('Optional: Existing Log Analytics Workspace Resource ID') +param existingLogAnalyticsWorkspaceId string = '' + +@description('Use this parameter to use an existing AI project resource ID') +param existingFoundryProjectResourceId string = '' + +@description('Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true.') +param vmSize string = '' + +@description('Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') +@secure() +param vmAdminUsername string = '' + +@description('Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') +@secure() +param vmAdminPassword string = '' + +@maxLength(5) +@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') +param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) + +var solutionSuffix = toLower(trim(replace( + replace( + replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), + ' ', + '' + ), + '*', + '' +))) +// ============== // +// Resources // +// ============== // + +var existingProjectResourceId = trim(existingFoundryProjectResourceId) + +// ========== AVM Telemetry ========== // +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.ptn.sa-contentprocessing.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. +var replicaRegionPairs = { + australiaeast: 'australiasoutheast' + centralus: 'westus' + eastasia: 'japaneast' + eastus: 'centralus' + eastus2: 'centralus' + japaneast: 'eastasia' + northeurope: 'westeurope' + southeastasia: 'eastasia' + uksouth: 'westeurope' + westeurope: 'northeurope' +} +var replicaLocation = replicaRegionPairs[?location] + +// ========== Virtual Network ========== // +module virtualNetwork './modules/networking/virtual-network.bicep' = if (enablePrivateNetworking) { + name: take('module.virtual-network.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + addressPrefixes: ['10.0.0.0/8'] + location: location + tags: tags + logAnalyticsWorkspaceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + resourceSuffix: solutionSuffix + enableTelemetry: enableTelemetry + } +} + +// Azure Bastion Host +var bastionHostName = 'bas-${solutionSuffix}' +module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePrivateNetworking) { + name: take('avm.res.network.bastion-host.${bastionHostName}', 64) + params: { + name: bastionHostName + skuName: 'Standard' + location: location + virtualNetworkResourceId: virtualNetwork!.outputs.resourceId + diagnosticSettings: enableMonitoring + ? [ + { + name: 'bastionDiagnostics' + workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + } + ] + : null + tags: tags + enableTelemetry: enableTelemetry + publicIPAddressObject: { + name: 'pip-${bastionHostName}' + } + } +} + +// ========== VM Maintenance Configuration Mapping ========== // + +// Jumpbox Virtual Machine +var jumpboxVmName = take('vm-${solutionSuffix}', 15) +module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enablePrivateNetworking) { + name: take('avm.res.compute.virtual-machine.${jumpboxVmName}', 64) + params: { + name: jumpboxVmName + location: location + tags: tags + enableTelemetry: enableTelemetry + computerName: take(jumpboxVmName, 15) + osType: 'Windows' + vmSize: empty(vmSize) ? 'Standard_D2s_v5' : vmSize + adminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername + adminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword + managedIdentities: { + systemAssigned: true + } + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId + enableAutomaticUpdates: true + encryptionAtHost: false + availabilityZone: enableRedundancy ? 1 : -1 + imageReference: { + publisher: 'microsoft-dsvm' + offer: 'dsvm-win-2022' + sku: 'winserver-2022' + version: 'latest' + } + osDisk: { + name: 'osdisk-${jumpboxVmName}' + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + // WAF aligned configuration - use Premium storage for better SLA when redundancy is enabled + storageAccountType: enableRedundancy ? 'Premium_LRS' : 'Standard_LRS' + } + } + nicConfigurations: [ + { + name: 'nic-${jumpboxVmName}' + tags: tags + deleteOption: 'Delete' + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : null + ipConfigurations: [ + { + name: '${jumpboxVmName}-nic01-ipconfig01' + subnetResourceId: virtualNetwork!.outputs.administrationSubnetResourceId + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : null + } + ] + } + ] + extensionAadJoinConfig: { + enabled: true + tags: tags + typeHandlerVersion: '1.0' + settings: { + mdmId:'' + } + } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: tags + } + //WAF aligned configuration for Monitoring + extensionMonitoringAgentConfig: enableMonitoring + ? { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId + name: 'send-${logAnalyticsWorkspace!.outputs.name}' + } + ] + enabled: true + tags: tags + } + : null + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: tags + } + } +} + +module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = if (enablePrivateNetworking) { + name: take('avm.res.maintenance-configuration.${jumpboxVmName}', 64) + params: { + name: 'mc-${jumpboxVmName}' + location: location + tags: tags + enableTelemetry: enableTelemetry + extensionProperties: { + InGuestPatchMode: 'User' + } + maintenanceScope: 'InGuestPatch' + maintenanceWindow: { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' + } + visibility: 'Custom' + installPatches: { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + } + } +} + +var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' +var dataCollectionRulesLocation = logAnalyticsWorkspace!.outputs.location +var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' +var dcrLogAnalyticsDestinationName = 'la-${logAnalyticsWorkspaceResourceName}-destination' +module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.11.0' = if (enablePrivateNetworking && enableMonitoring) { + name: take('avm.res.insights.data-collection-rule.${dataCollectionRulesResourceName}', 64) + params: { + name: dataCollectionRulesResourceName + tags: tags + enableTelemetry: enableTelemetry + location: dataCollectionRulesLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + performanceCounters: [ + { + streams: [ + 'Microsoft-Perf' + ] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' + } + ] + windowsEventLogs: [ + { + name: 'SecurityAuditEvents' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' + ] + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId + name: dcrLogAnalyticsDestinationName + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + { + streams: [ + 'Microsoft-Event' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + transformKql: 'source' + outputStream: 'Microsoft-Event' + } + ] + } + } +} + +// ========== Private DNS Zones ========== // +var privateDnsZones = [ + 'privatelink.cognitiveservices.azure.com' + 'privatelink.openai.azure.com' + 'privatelink.services.ai.azure.com' + 'privatelink.contentunderstanding.ai.azure.com' + 'privatelink.blob.${environment().suffixes.storage}' + 'privatelink.queue.${environment().suffixes.storage}' + 'privatelink.mongo.cosmos.azure.com' + 'privatelink.azconfig.io' + 'privatelink.azurecr.io' +] + +// DNS Zone Index Constants +var dnsZoneIndex = { + cognitiveServices: 0 + openAI: 1 + aiServices: 2 + contentUnderstanding: 3 + storageBlob: 4 + storageQueue: 5 + cosmosDB: 6 + appConfig: 7 + containerRegistry: 8 +} + +@batchSize(5) +module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ + for (zone, i) in privateDnsZones: if (enablePrivateNetworking) { + name: take('avm.res.network.private-dns-zone.${split(zone, '.')[1]}', 64) + params: { + name: zone + tags: tags + enableTelemetry: enableTelemetry + virtualNetworkLinks: [{ virtualNetworkResourceId: virtualNetwork!.outputs.resourceId }] + } + } +] + +// ========== Log Analytics & Application Insights ========== // +module logAnalyticsWorkspace './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { + name: take('module.log-analytics-workspace.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: logAnalyticsWorkspaceResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + enableReplication: enableRedundancy + replicationLocation: replicaLocation + } +} + +module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (enableMonitoring) { + name: take('avm.res.insights.component.${solutionSuffix}', 64) + params: { + name: 'appi-${solutionSuffix}' + location: location + enableTelemetry: enableTelemetry + retentionInDays: 365 + kind: 'web' + disableIpMasking: false + flowType: 'Bluefield' + // WAF aligned configuration for Monitoring + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null + tags: tags + } +} + +@description('Optional. Tag, Created by user name.') +param createdBy string = contains(deployer(), 'userPrincipalName') + ? split(deployer().userPrincipalName, '@')[0] + : deployer().objectId + +// ========== Resource Group Tag ========== // +resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { + name: 'default' + properties: { + tags: { + ...resourceGroup().tags + ...tags + TemplateName: 'Content Processing' + Type: enablePrivateNetworking ? 'WAF' : 'Non-WAF' + CreatedBy: createdBy + DeploymentName: deployment().name + } + } +} + +// ========== Managed Identity ========== // +module avmManagedIdentity './modules/identity/managed-identity.bicep' = { + name: take('module.managed-identity.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + identityName: 'id-${solutionSuffix}' + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +module avmContainerRegistry './modules/compute/container-registry.bicep' = { + name: take('module.container-registry.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: 'cr${replace(solutionSuffix, '-', '')}' + location: location + sku: enableRedundancy || enablePrivateNetworking ? 'Premium' : 'Standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + acrPullPrincipalIds: [ + avmContainerRegistryReader.outputs.principalId + ] + tags: tags + enableTelemetry: enableTelemetry + enablePrivateNetworking: enablePrivateNetworking + privateEndpointSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.backendSubnetResourceId : '' + privateDnsZoneResourceIds: enablePrivateNetworking + ? [avmPrivateDnsZones[dnsZoneIndex.containerRegistry]!.outputs.resourceId] + : [] + } +} + +// // ========== Storage Account ========== // +module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { + name: take('module.storage-account.${solutionSuffix}', 64) + params: { + name: 'st${replace(solutionSuffix, '-', '')}' + location: location + managedIdentities: { systemAssigned: true } + minimumTlsVersion: 'TLS1_2' + enableTelemetry: enableTelemetry + roleAssignments: [ + { + principalId: avmManagedIdentity.outputs.principalId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' + ipRules: [] + } + requireInfrastructureEncryption: true + supportsHttpsTrafficOnly: true + accessTier: 'Hot' + tags: tags + + //<======================= WAF related parameters + allowBlobPublicAccess: false + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + privateEndpoints: (enablePrivateNetworking) + ? [ + { + name: 'pep-blob-${solutionSuffix}' + customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'storage-dns-zone-group-blob' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + service: 'blob' + } + { + name: 'pep-queue-${solutionSuffix}' + customNetworkInterfaceName: 'nic-queue-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'storage-dns-zone-group-queue' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageQueue]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + service: 'queue' + } + ] + : [] + } +} + +// // ========== AI Foundry and related resources ========== // +module avmAiServices './modules/ai/ai-foundry.bicep' = { + name: take('module.ai-services.${solutionSuffix}', 64) + params: { + name: 'aif-${solutionSuffix}' + projectName: 'proj-${solutionSuffix}' + projectDescription: 'proj-${solutionSuffix}' + existingFoundryProjectResourceId: existingProjectResourceId + location: azureAiServiceLocation + sku: 'S0' + allowProjectManagement: true + managedIdentities: { systemAssigned: true } + kind: 'AIServices' + tags: { + app: solutionSuffix + location: azureAiServiceLocation + } + customSubDomainName: 'aif-${solutionSuffix}' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null + roleAssignments: [ + { + principalId: avmManagedIdentity.outputs.principalId + roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' + } + disableLocalAuth: true + enableTelemetry: enableTelemetry + deployments: [ + { + name: gptModelName + model: { + format: 'OpenAI' + name: gptModelName + version: gptModelVersion + } + sku: { + name: deploymentType + capacity: gptDeploymentCapacity + } + raiPolicyName: 'Microsoft.Default' + } + ] + + // WAF related parameters + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + //publicNetworkAccess: 'Enabled' // Always enabled for AI Services + } +} + +module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking && empty(existingProjectResourceId)) { + name: take('avm.res.network.private-endpoint.${solutionSuffix}', 64) + params: { + name: 'pep-aiservices-${solutionSuffix}' + location: location + tags: tags + customNetworkInterfaceName: 'nic-aiservices-${solutionSuffix}' + privateLinkServiceConnections: [ + { + name: 'pep-aiservices-${solutionSuffix}-cognitiveservices-connection' + properties: { + privateLinkServiceId: avmAiServices.outputs.resourceId + groupIds: ['account'] + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'ai-services-dns-zone-cognitiveservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-openai' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-aiservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-contentunderstanding' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId + } +} + +// ========== Container App Environment ========== // +module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { + name: take('avm.res.app.managed-environment.${solutionSuffix}', 64) + params: { + name: 'cae-${solutionSuffix}' + location: location + tags: { + ...resourceGroup().tags + ...tags + } + managedIdentities: { systemAssigned: true } + appLogsConfiguration: enableMonitoring + ? { + destination: 'log-analytics' + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId + } + : null + workloadProfiles: [ + { + name: 'Consumption' + workloadProfileType: 'Consumption' + } + ] + enableTelemetry: enableTelemetry + publicNetworkAccess: 'Enabled' // Always enabled for Container Apps Environment + + // <========== WAF related parameters + + platformReservedCidr: '172.17.17.0/24' + platformReservedDnsIP: '172.17.17.17' + zoneRedundant: (enablePrivateNetworking) ? true : false // Enable zone redundancy if private networking is enabled + infrastructureSubnetResourceId: (enablePrivateNetworking) + ? virtualNetwork!.outputs.webserverfarmSubnetResourceId // Use the container app subnet + : null // Use the container app subnet + } +} + +// //=========== Managed Identity for Container Registry ========== // +module avmContainerRegistryReader 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { + name: take('avm.res.managed-identity.user-assigned-identity.${solutionSuffix}', 64) + params: { + name: 'id-acr-${solutionSuffix}' + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ========== Container App ========== // +module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-app' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + + containers: [ + { + name: 'ca-${solutionSuffix}' + image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' + + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: '' + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + tags: tags + } +} + +// ========== Container App API ========== // +module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-api.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-api' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-api' + image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: '' + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ] + probes: [ + // Liveness Probe - Checks if the app is still running + { + type: 'Liveness' + httpGet: { + path: '/startup' // Your app must expose this endpoint + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + // Readiness Probe - Checks if the app is ready to receive traffic + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 // Wait 10s before checking + periodSeconds: 5 // Check every 15s + failureThreshold: 10 // Restart if it fails 5 times + } + ] + } + ] + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] + } + ingressExternal: true + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + corsPolicy: { + allowedOrigins: [ + '*' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + 'Authorization' + 'Content-Type' + '*' + ] + } + } +} + +//========== Container App Web ========== // +module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-web.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-web' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + ingressExternal: true + ingressTargetPort: 3000 + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-web' + image: '${containerRegistryEndpoint}/contentprocessorweb:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_API_BASE_URL' + value: 'https://${avmContainerApp_API.outputs.fqdn}' + } + { + name: 'APP_WEB_CLIENT_ID' + value: '' + } + { + name: 'APP_WEB_AUTHORITY' + value: '${environment().authentication.loginEndpoint}/${tenant().tenantId}' + } + { + name: 'APP_WEB_SCOPE' + value: '' + } + { + name: 'APP_API_SCOPE' + value: '' + } + { + name: 'APP_REDIRECT_URL' + value: '/' + } + { + name: 'APP_POST_REDIRECT_URL' + value: '/' + } + { + name: 'APP_CONSOLE_LOG_ENABLED' + value: 'false' + } + ] + } + ] + } +} + +// ========== Container App Workflow ========== // +module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-wkfl.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-wkfl' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-wkfl' + image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: '' + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + } +} + +// ========== Cosmos Database for Mongo DB ========== // +module avmCosmosDB 'br/public:avm/res/document-db/database-account:0.19.0' = { + name: take('avm.res.document-db.database-account.${solutionSuffix}', 64) + params: { + name: 'cosmos-${solutionSuffix}' + location: location + mongodbDatabases: [ + { + name: 'default' + tag: 'default database' + } + ] + tags: tags + enableTelemetry: enableTelemetry + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + serverVersion: '7.0' + capabilitiesToAdd: [ + 'EnableMongo' + ] + defaultConsistencyLevel: 'Session' + maxIntervalInSeconds: 5 + maxStalenessPrefix: 100 + zoneRedundant: false + + // WAF related parameters + networkRestrictions: { + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + ipRules: [] + virtualNetworkRules: [] + } + + privateEndpoints: (enablePrivateNetworking) + ? [ + { + name: 'pep-cosmosdb-${solutionSuffix}' + customNetworkInterfaceName: 'nic-cosmosdb-${solutionSuffix}' + privateEndpointResourceId: virtualNetwork!.outputs.resourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'cosmosdb-dns-zone-group' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId + } + ] + } + service: 'MongoDB' + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + } + ] + : [] + } +} + +// ========== AI Search ========== // +module avmAiSearch './modules/ai/ai-search.bicep' = { + name: take('module.ai-search.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: 'srch-${solutionSuffix}' + location: location + skuName: 'basic' + replicaCount: enableRedundancy ? 2 : 1 + partitionCount: enableScalability ? 2 : 1 + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ========== App Configuration ========== // +module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { + name: take('avm.res.app.configuration-store.${solutionSuffix}', 64) + params: { + name: 'appcs-${solutionSuffix}' + location: location + enablePurgeProtection: enablePurgeProtection + tags: { + app: solutionSuffix + location: location + } + enableTelemetry: enableTelemetry + managedIdentities: { systemAssigned: true } + sku: 'Standard' + diagnosticSettings: enableMonitoring + ? [ + { + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + } + ] + : null + disableLocalAuth: false + replicaLocations: enableRedundancy? [{ replicaLocation: replicaLocation }] : [] + roleAssignments: [ + { + principalId: avmContainerApp.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_API.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Web.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + ] + keyValues: [ + { + name: 'APP_AZURE_OPENAI_ENDPOINT' + value: avmAiServices.outputs.endpoint //TODO: replace with actual endpoint + } + { + name: 'APP_AZURE_OPENAI_MODEL' + value: gptModelName + } + { + name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + { + name: 'APP_COSMOS_CONTAINER_PROCESS' + value: 'Processes' + } + { + name: 'APP_COSMOS_CONTAINER_SCHEMA' + value: 'Schemas' + } + { + name: 'APP_COSMOS_DATABASE' + value: 'ContentProcess' + } + { + name: 'APP_CPS_CONFIGURATION' + value: 'cps-configuration' + } + { + name: 'APP_CPS_MAX_FILESIZE_MB' + value: '20' + } + { + name: 'APP_CPS_PROCESSES' + value: 'cps-processes' + } + { + name: 'APP_MESSAGE_QUEUE_EXTRACT' + value: 'content-pipeline-extract-queue' + } + { + name: 'APP_MESSAGE_QUEUE_INTERVAL' + value: '5' + } + { + name: 'APP_MESSAGE_QUEUE_PROCESS_TIMEOUT' + value: '180' + } + { + name: 'APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT' + value: '10' + } + { + name: 'APP_PROCESS_STEPS' + value: 'extract,map,evaluate,save' + } + { + name: 'APP_STORAGE_BLOB_URL' + value: avmStorageAccount.outputs.serviceEndpoints.blob + } + { + name: 'APP_STORAGE_QUEUE_URL' + value: avmStorageAccount.outputs.serviceEndpoints.queue + } + { + name: 'APP_AI_PROJECT_ENDPOINT' + value: avmAiServices.outputs.aiProjectInfo.?apiEndpoint ?? '' + } + { + name: 'APP_COSMOS_CONNSTR' + value: avmCosmosDB.outputs.primaryReadWriteConnectionString + } + // ===== v2 Workflow Keys ===== // + { + name: 'APP_COSMOS_CONTAINER_BATCH_PROCESS' + value: 'claimprocesses' + } + { + name: 'APP_COSMOS_CONTAINER_BATCHES' + value: 'batches' + } + { + name: 'APP_COSMOS_CONTAINER_SCHEMASET' + value: 'Schemasets' + } + { + name: 'APP_CPS_PROCESS_BATCH' + value: 'process-batch' + } + { + name: 'APP_CPS_CONTENT_PROCESS_ENDPOINT' + value: 'http://${avmContainerApp_API.outputs.name}/' + } + { + name: 'APP_CPS_POLL_INTERVAL_SECONDS' + value: '3' + } + { + name: 'APP_STORAGE_ACCOUNT_NAME' + value: avmStorageAccount.outputs.name + } + { + name: 'CLAIM_PROCESS_QUEUE_NAME' + value: 'claim-process-queue' + } + { + name: 'DEAD_LETTER_QUEUE_NAME' + value: 'claim-process-dead-letter-queue' + } + { + name: 'AZURE_OPENAI_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + { + name: 'AZURE_OPENAI_CHAT_DEPLOYMENT_NAME' + value: gptModelName + } + { + name: 'AZURE_OPENAI_API_VERSION' + value: '2025-03-01-preview' + } + { + name: 'AZURE_OPENAI_ENDPOINT_BASE' + value: avmAiServices.outputs.endpoint + } + // ===== Agent Framework Keys ===== // + { + name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' + value: '' + } + { + name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' + value: '' + } + { + name: 'AZURE_TRACING_ENABLED' + value: 'True' + } + { + name: 'GLOBAL_LLM_SERVICE' + value: 'AzureOpenAI' + } + // ===== GPT-5 Service Prefix Keys ===== // + { + name: 'GPT5_API_VERSION' + value: '2025-03-01-preview' + } + { + name: 'GPT5_CHAT_DEPLOYMENT_NAME' + value: 'gpt-5' + } + { + name: 'GPT5_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + // ===== PHI-4 Service Prefix Keys ===== // + { + name: 'PHI4_API_VERSION' + value: '2024-05-01-preview' + } + { + name: 'PHI4_CHAT_DEPLOYMENT_NAME' + value: 'phi-4' + } + { + name: 'PHI4_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + ] + + publicNetworkAccess: 'Enabled' + } +} + +module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = if (enablePrivateNetworking) { + name: take('avm.res.app.configuration-store.update.${solutionSuffix}', 64) + params: { + name: 'appcs-${solutionSuffix}' + location: location + enablePurgeProtection: enablePurgeProtection + enableTelemetry: enableTelemetry + tags: tags + publicNetworkAccess: 'Disabled' + privateEndpoints: [ + { + name: 'pep-appconfig-${solutionSuffix}' + customNetworkInterfaceName: 'nic-appconfig-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'appconfig-dns-zone-group' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.appConfig]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + } + ] + } + + dependsOn: [ + avmAppConfig + ] +} + +// ========== Container App Update Modules ========== // +module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-update.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-app' + location: location + enableTelemetry: enableTelemetry + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}' + image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' + + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: enableScalability + ? [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: 100 + } + } + } + ] + : [] + } + } + dependsOn: [ + cognitiveServicePrivateEndpoint + ] +} + +module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-api' + location: location + enableTelemetry: enableTelemetry + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + + containers: [ + { + name: 'ca-${solutionSuffix}-api' + image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ] + probes: [ + // Liveness Probe - Checks if the app is still running + { + type: 'Liveness' + httpGet: { + path: '/startup' // Your app must expose this endpoint + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + // Readiness Probe - Checks if the app is ready to receive traffic + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 // Wait 10s before checking + periodSeconds: 5 // Check every 15s + failureThreshold: 10 // Restart if it fails 5 times + } + ] + } + ] + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] + } + ingressExternal: true + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + corsPolicy: { + allowedOrigins: [ + '*' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + 'Authorization' + 'Content-Type' + '*' + ] + } + } + dependsOn: [ + cognitiveServicePrivateEndpoint + ] +} + +// ========== Container App Workflow Update ========== // +module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-wkfl' + location: location + enableTelemetry: enableTelemetry + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-wkfl' + image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The name of the Container App used for Web App.') +output CONTAINER_WEB_APP_NAME string = avmContainerApp_Web.outputs.name + +@description('The name of the Container App used for API.') +output CONTAINER_API_APP_NAME string = avmContainerApp_API.outputs.name + +@description('The FQDN of the Container App.') +output CONTAINER_WEB_APP_FQDN string = avmContainerApp_Web.outputs.fqdn + +@description('The FQDN of the Container App API.') +output CONTAINER_API_APP_FQDN string = avmContainerApp_API.outputs.fqdn + +@description('The name of the Container App used for APP.') +output CONTAINER_APP_NAME string = avmContainerApp.outputs.name + +@description('The name of the Container App used for Workflow.') +output CONTAINER_WORKFLOW_APP_NAME string = avmContainerApp_Workflow.outputs.name + +@description('The user identity resource ID used fot the Container APP.') +output CONTAINER_APP_USER_IDENTITY_ID string = avmContainerRegistryReader.outputs.resourceId + +@description('The user identity Principal ID used fot the Container APP.') +output CONTAINER_APP_USER_PRINCIPAL_ID string = avmContainerRegistryReader.outputs.principalId + +@description('The name of the Azure Container Registry.') +output CONTAINER_REGISTRY_NAME string = avmContainerRegistry.outputs.name + +@description('The login server of the Azure Container Registry.') +output CONTAINER_REGISTRY_LOGIN_SERVER string = avmContainerRegistry.outputs.loginServer + +@description('The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA.') +output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices.outputs.name + +@description('The resource group the resources were deployed into.') +output AZURE_RESOURCE_GROUP string = resourceGroup().name + +@description('The solution name.') +output SOLUTION_NAME string = solutionName diff --git a/infra/avm/main.json b/infra/avm/main.json new file mode 100644 index 00000000..eabf3776 --- /dev/null +++ b/infra/avm/main.json @@ -0,0 +1,68661 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17324347463484125167" + }, + "name": "Content Processing Solution Accelerator", + "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." + }, + "parameters": { + "solutionName": { + "type": "string", + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20, + "metadata": { + "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." + } + }, + "location": { + "type": "string", + "allowedValues": [ + "australiaeast", + "centralus", + "eastasia", + "eastus2", + "japaneast", + "northeurope", + "southeastasia", + "uksouth" + ], + "metadata": { + "azd": { + "type": "location" + }, + "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." + } + }, + "azureAiServiceLocation": { + "type": "string", + "allowedValues": [ + "australiaeast", + "eastus", + "eastus2", + "japaneast", + "southcentralus", + "southeastasia", + "swedencentral", + "uksouth", + "westeurope", + "westus", + "westus3" + ], + "metadata": { + "azd": { + "type": "location", + "usageName": [ + "OpenAI.GlobalStandard.gpt-5.1,300" + ] + }, + "description": "Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead." + }, + "minLength": 1 + }, + "deploymentType": { + "type": "string", + "defaultValue": "GlobalStandard", + "allowedValues": [ + "Standard", + "GlobalStandard" + ], + "minLength": 1, + "metadata": { + "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." + } + }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1", + "metadata": { + "description": "Optional. Name of the GPT model to deploy: gpt-5.1" + } + }, + "gptModelVersion": { + "type": "string", + "defaultValue": "2025-11-13", + "allowedValues": [ + "2025-11-13" + ], + "minLength": 1, + "metadata": { + "description": "Optional. Version of the GPT model to deploy:." + } + }, + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": 300, + "minValue": 1, + "metadata": { + "description": "Optional. Capacity of the GPT deployment: (minimum 10)." + } + }, + "containerRegistryEndpoint": { + "type": "string", + "defaultValue": "cpscontainerreg.azurecr.io", + "metadata": { + "description": "Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint)." + } + }, + "imageTag": { + "type": "string", + "defaultValue": "latest_v2", + "metadata": { + "description": "Optional. The image tag for the container images." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable WAF for the deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + } + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enableScalability": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable purge protection. Defaults to false." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" + }, + "description": "Optional. Tags to be applied to the resources." + }, + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + } + }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Existing Log Analytics Workspace Resource ID" + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Use this parameter to use an existing AI project resource ID" + } + }, + "vmSize": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminUsername": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." + } + }, + "createdBy": { + "type": "string", + "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", + "metadata": { + "description": "Optional. Tag, Created by user name." + } + } + }, + "variables": { + "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", + "existingProjectResourceId": "[trim(parameters('existingFoundryProjectResourceId'))]", + "replicaRegionPairs": { + "australiaeast": "australiasoutheast", + "centralus": "westus", + "eastasia": "japaneast", + "eastus": "centralus", + "eastus2": "centralus", + "japaneast": "eastasia", + "northeurope": "westeurope", + "southeastasia": "eastasia", + "uksouth": "westeurope", + "westeurope": "northeurope" + }, + "replicaLocation": "[tryGet(variables('replicaRegionPairs'), parameters('location'))]", + "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", + "jumpboxVmName": "[take(format('vm-{0}', variables('solutionSuffix')), 15)]", + "dataCollectionRulesResourceName": "[format('dcr-{0}', variables('solutionSuffix'))]", + "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", + "dcrLogAnalyticsDestinationName": "[format('la-{0}-destination', variables('logAnalyticsWorkspaceResourceName'))]", + "privateDnsZones": [ + "privatelink.cognitiveservices.azure.com", + "privatelink.openai.azure.com", + "privatelink.services.ai.azure.com", + "privatelink.contentunderstanding.ai.azure.com", + "[format('privatelink.blob.{0}', environment().suffixes.storage)]", + "[format('privatelink.queue.{0}', environment().suffixes.storage)]", + "privatelink.mongo.cosmos.azure.com", + "privatelink.azconfig.io", + "privatelink.azurecr.io" + ], + "dnsZoneIndex": { + "cognitiveServices": 0, + "openAI": 1, + "aiServices": 2, + "contentUnderstanding": 3, + "storageBlob": 4, + "storageQueue": 5, + "cosmosDB": 6, + "appConfig": 7, + "containerRegistry": 8 + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('46d3xbcp.ptn.sa-contentprocessing.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroupTags": { + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", + "properties": { + "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" + } + }, + "virtualNetwork": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "addressPrefixes": { + "value": [ + "10.0.0.0/8" + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "resourceSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "10323079586505814920" + } + }, + "definitions": { + "subnetOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the subnet." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the subnet." + } + }, + "nsgName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The name of the associated NSG, if any." + } + }, + "nsgResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The resource ID of the associated NSG, if any." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Subnet output type" + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. Address prefixes for the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Delegation for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Private endpoint network policies." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Private link service network policies." + } + }, + "networkSecurityGroup": { + "$ref": "#/definitions/networkSecurityGroupType", + "nullable": true, + "metadata": { + "description": "Optional. NSG configuration for the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Route table resource ID." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Service endpoints to enable." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable default outbound connectivity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Subnet configuration type" + } + }, + "networkSecurityGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NSG." + } + }, + "securityRules": { + "type": "array", + "items": { + "type": "object" + }, + "metadata": { + "description": "Required. Security rules for the NSG." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "NSG configuration type" + } + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Azure region for the resource." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Address prefixes for the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "defaultValue": [ + { + "name": "backend", + "addressPrefixes": [ + "10.0.0.0/27" + ], + "networkSecurityGroup": { + "name": "nsg-backend", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "webserverfarm", + "addressPrefixes": [ + "10.0.4.0/27" + ], + "delegation": "Microsoft.Web/serverfarms", + "privateEndpointNetworkPolicies": "Enabled", + "privateLinkServiceNetworkPolicies": "Enabled", + "networkSecurityGroup": { + "name": "nsg-webserverfarm", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "administration", + "addressPrefixes": [ + "10.0.0.32/27" + ], + "networkSecurityGroup": { + "name": "nsg-administration", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "AzureBastionSubnet", + "addressPrefixes": [ + "10.0.0.64/26" + ], + "networkSecurityGroup": { + "name": "nsg-bastion", + "securityRules": [ + { + "name": "AllowGatewayManager", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2702, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "GatewayManager", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowHttpsInBound", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2703, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowSshRdpOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 100, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AllowAzureCloudOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 110, + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "AzureCloud" + } + } + ] + } + } + ], + "metadata": { + "description": "Subnet configurations." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resources." + } + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics Workspace for diagnostics." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceSuffix": { + "type": "string", + "metadata": { + "description": "Suffix for resource naming." + } + } + }, + "variables": { + "name": "[format('vnet-{0}', parameters('solutionName'))]" + }, + "resources": { + "nsgs": { + "copy": { + "name": "nsgs", + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "securityRules": { + "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7311263652424030280" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG)." + }, + "definitions": { + "securityRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "properties": { + "type": "object", + "properties": { + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the security rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 4096, + "metadata": { + "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "metadata": { + "description": "Required. The properties of the security rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a security rule." + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "securityRules": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" + }, + "description": "Optional. Tags of the NSG resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(coalesce(parameters('securityRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "properties": { + "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", + "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", + "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", + "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", + "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", + "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", + "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", + "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", + "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", + "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", + "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", + "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", + "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", + "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", + "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { + "copy": { + "name": "networkSecurityGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "addressPrefixes": { + "value": "[parameters('addressPrefixes')]" + }, + "subnets": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('subnets'))]", + "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "name": "vnetDiagnostics", + "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs", + "enabled": true + } + ], + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11272001757446231867" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet)." + }, + "definitions": { + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "prefixItems": [ + { + "type": "object", + "properties": { + "pool": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + } + }, + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + }, + "numberOfIpAddresses": { + "type": "string", + "metadata": { + "description": "Required. Number of IP addresses allocated from the pool." + } + } + } + } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." + } + }, + "ipamPoolNumberOfIpAddresses": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + }, + "enablePrivateEndpointVNetPolicies": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Basic", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]", + "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "ipamPoolPrefixAllocations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13992200806189615656" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + } + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "metadata": { + "description": "The IPAM pool prefix allocations for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "nsgs" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.name.value]" + }, + "resourceId": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetOutputType" + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex()].name]", + "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", + "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", + "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" + } + } + }, + "backendSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" + }, + "webserverfarmSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" + }, + "administrationSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" + }, + "bastionSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "bastionHost": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('bastionHostName')]" + }, + "skuName": { + "value": "Standard" + }, + "location": { + "value": "[parameters('location')]" + }, + "virtualNetworkResourceId": { + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": { + "name": "[format('pip-{0}', variables('bastionHostName'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7741601918225805390" + }, + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host." + }, + "definitions": { + "publicIPAddressObjectType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for the Public IP resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create for the Public IP resource." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the Public IP module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Idle timeout in minutes for the Public IP resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to apply to the Public IP resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the Public IP resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Bastion resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Shared services Virtual Network resource Id." + } + }, + "bastionSubnetPublicIpResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "publicIPAddressObject": { + "$ref": "#/definitions/publicIPAddressObjectType", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Developer", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. The SKU of this Bastion Host." + } + }, + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." + } + }, + "enableFileCopy": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." + } + }, + "enableIpConnect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." + } + }, + "enableKerberos": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." + } + }, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." + } + }, + "enableSessionRecording": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." + } + }, + "enablePrivateOnlyBastion": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." + } + }, + "scaleUnits": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. The list of Availability zones to use for the zone-redundant resources." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[coalesce(parameters('tags'), createObject())]", + "sku": { + "name": "[parameters('skuName')]" + }, + "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", + "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] + }, + "azureBastion_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_diagnosticSettings": { + "copy": { + "name": "azureBastion_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "publicIPAddress": { + "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" + }, + "ipTags": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "16564959277054027786" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "deleteOption": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Delete", + "Detach" + ], + "metadata": { + "description": "Optional. The delete option for the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure Bastion was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name the Azure Bastion." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID the Azure Bastion." + }, + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureBastion', '2025-01-01', 'full').location]" + }, + "ipConfAzureBastionSubnet": { + "type": "object", + "metadata": { + "description": "The Public IPconfiguration object for the AzureBastionSubnet." + }, + "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "virtualNetwork" + ] + }, + "jumpboxVM": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('jumpboxVmName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "computerName": { + "value": "[take(variables('jumpboxVmName'), 15)]" + }, + "osType": { + "value": "Windows" + }, + "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", + "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", + "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": true + }, + "maintenanceConfigurationResourceId": { + "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", + "imageReference": { + "value": { + "publisher": "microsoft-dsvm", + "offer": "dsvm-win-2022", + "sku": "winserver-2022", + "version": "latest" + } + }, + "osDisk": { + "value": { + "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" + } + } + }, + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-{0}', variables('jumpboxVmName'))]", + "tags": "[parameters('tags')]", + "deleteOption": "Delete", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", + "ipConfigurations": [ + { + "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", + "subnetResourceId": "[reference('virtualNetwork').outputs.administrationSubnetResourceId.value]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" + } + ] + } + ] + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]", + "typeHandlerVersion": "1.0", + "settings": { + "mdmId": "" + } + } + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": {}, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + }, + "tags": "[parameters('tags')]" + } + }, + "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17174537341033050778" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." + }, + "definitions": { + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "diffDiskSettings": { + "type": "object", + "properties": { + "placement": { + "type": "string", + "allowedValues": [ + "CacheDisk", + "NvmeDisk", + "ResourceDisk" + ], + "metadata": { + "description": "Required. Specifies the ephemeral disk placement for the operating system disk." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing an OS disk." + } + }, + "dataDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" + }, + "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a data disk." + } + }, + "publicKeyType": { + "type": "object", + "properties": { + "keyData": { + "type": "string", + "metadata": { + "description": "Required. Specifies the SSH public key data used to authenticate through ssh." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." + } + } + } + }, + "nicConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the NIC configuration." + } + }, + "nicSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The suffix to append to the NIC name." + } + }, + "enableIPForwarding": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify what happens to the network interface when the VM is deleted." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "metadata": { + "description": "Required. The IP configurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the NIC configuration." + } + }, + "imageReferenceType": { + "type": "object", + "properties": { + "communityGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." + } + }, + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource Id of the image reference." + } + }, + "offer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The image publisher." + } + }, + "sku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SKU of the image." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." + } + }, + "sharedGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the image reference." + } + }, + "planType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the plan." + } + }, + "product": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the product of the image from the marketplace." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher ID." + } + }, + "promotionCode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The promotion code." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Specifies information about the marketplace image used to create the virtual machine." + } + }, + "autoShutDownConfigType": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the auto shutdown configuration." + } + }, + "timeZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." + } + }, + "dailyRecurrenceTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time of day the schedule will occur." + } + }, + "notificationSettings": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the notification settings." + } + }, + "emailRecipient": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." + } + }, + "notificationLocale": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + } + }, + "webhookUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The webhook URL to which the notification will be sent." + } + }, + "timeInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The time in minutes before shutdown to send notifications." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the schedule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the configuration profile." + } + }, + "vaultSecretGroupType": { + "type": "object", + "properties": { + "sourceVault": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." + } + }, + "vaultCertificates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "certificateStore": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + } + }, + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of key vault references in SourceVault which contain certificates." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the set of certificates that should be installed onto the virtual machine." + } + }, + "vmGalleryApplicationType": { + "type": "object", + "properties": { + "packageReferenceId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." + } + }, + "configurationReference": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." + } + }, + "order": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the order in which the packages have to be installed." + } + }, + "tags": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies a passthrough value for more generic context." + } + }, + "treatFailureAsDeploymentFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the gallery application that should be made available to the VM/VMSS." + } + }, + "additionalUnattendContentType": { + "type": "object", + "properties": { + "settingName": { + "type": "string", + "allowedValues": [ + "AutoLogon", + "FirstLogonCommands" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the setting to which the content applies." + } + }, + "content": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." + } + }, + "winRMListenerType": { + "type": "object", + "properties": { + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Http", + "Https" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the protocol of WinRM listener." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a Windows Remote Management listener." + } + }, + "nicConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NIC configuration." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "Required. List of IP configurations of the NIC configuration." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the network interface configuration output." + } + }, + "extensionCustomScriptConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." + } + }, + "typeHandlerVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "protectedSettings": { + "type": "secureObject", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." + } + }, + "storageAccountName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." + } + }, + "storageAccountKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The access key of the storage account." + } + }, + "managedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "supressFailures": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a 'CustomScriptExtension' extension." + } + }, + "_1.applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_2.ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_2.dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_2.ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_3.diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_4.publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/_3.lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/_2.ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/_2.dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "description": "The type for the public IP address configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/_4.publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "description": "The type for the IP configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "description": "The type for the network interface IP configuration output.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" + }, + "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." + }, + "nullable": true + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" + }, + "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." + }, + "nullable": true + }, + "plan": { + "$ref": "#/definitions/planType", + "nullable": true, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "type": "array", + "items": { + "$ref": "#/definitions/dataDiskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "hibernationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables hibernation capability on the VM." + } + }, + "adminUsername": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." + } + }, + "userData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "items": { + "$ref": "#/definitions/vaultSecretGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "Deallocate", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "publicKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/publicKeyType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "galleryApplications": { + "type": "array", + "items": { + "$ref": "#/definitions/vmGalleryApplicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." + } + }, + "availabilityZone": { + "type": "int", + "allowedValues": [ + -1, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." + } + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationType" + }, + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Recovery service vault name to add VMs to backup." + } + }, + "backupVaultResourceGroup": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "DefaultPolicy", + "metadata": { + "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + } + }, + "autoShutdownConfig": { + "$ref": "#/definitions/autoShutDownConfigType", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for auto-shutdown." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource Id of a maintenance configuration for this VM." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "dataCollectionRuleAssociations": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "$ref": "#/definitions/extensionCustomScriptConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionHostPoolRegistration": { + "type": "secureObject", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "extensionGuestConfigurationExtension": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "guestConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." + } + }, + "extensionGuestConfigurationExtensionProtectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "disablePasswordAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether password authentication should be disabled." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "enableHotpatching": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "items": { + "$ref": "#/definitions/additionalUnattendContentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRMListeners": { + "type": "array", + "items": { + "$ref": "#/definitions/winRMListenerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + }, + "capacityReservationGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." + } + }, + "networkAccessPolicy": { + "type": "string", + "defaultValue": "DenyAll", + "allowedValues": [ + "AllowAll", + "AllowPrivate", + "DenyAll" + ], + "metadata": { + "description": "Optional. Policy for accessing the disk via network." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Policy for controlling export on the disk." + } + } + }, + "variables": { + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" + } + }, + { + "name": "additionalUnattendContentFormatted", + "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", + "input": { + "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", + "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", + "componentName": "Microsoft-Windows-Shell-Setup", + "passName": "OobeSystem" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", + "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" + }, + "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", + "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "managedDataDisks": { + "copy": { + "name": "managedDataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" + }, + "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", + "type": "Microsoft.Compute/disks", + "apiVersion": "2025-01-02", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", + "location": "[parameters('location')]", + "sku": { + "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" + }, + "properties": { + "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", + "creationData": { + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" + }, + "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", + "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "networkAccessPolicy": "[parameters('networkAccessPolicy')]" + }, + "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", + "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", + "plan": "[parameters('plan')]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", + "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", + "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", + "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", + "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", + "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", + "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", + "osType": "[parameters('osType')]", + "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", + "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", + "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", + "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", + "managedDisk": { + "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", + "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", + "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", + "hibernationEnabled": "[parameters('hibernationEnabled')]" + }, + "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" + } + } + ] + }, + "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", + "licenseType": "[parameters('licenseType')]", + "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" + }, + "dependsOn": [ + "managedDataDisks", + "vm_nic" + ] + }, + "vm_configurationAssignment": { + "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", + "type": "Microsoft.Maintenance/configurationAssignments", + "apiVersion": "2023-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[format('{0}assignment', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", + "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_autoShutdownConfiguration": { + "condition": "[not(empty(parameters('autoShutdownConfig')))]", + "type": "Microsoft.DevTestLab/schedules", + "apiVersion": "2018-09-15", + "name": "[format('shutdown-computevm-{0}', parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", + "properties": { + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", + "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "taskType": "ComputeVmShutdownTask", + "dailyRecurrence": { + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" + }, + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_dataCollectionRuleAssociations": { + "copy": { + "name": "vm_dataCollectionRuleAssociations", + "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" + }, + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2024-03-11", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", + "properties": { + "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "cseIdentity": { + "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", + "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" + }, + "AzureWindowsBaseline": { + "condition": "[not(empty(parameters('guestConfiguration')))]", + "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", + "apiVersion": "2024-04-05", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", + "location": "[parameters('location')]", + "properties": { + "guestConfiguration": "[parameters('guestConfiguration')]" + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + }, + "vm_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_roleAssignments": { + "copy": { + "name": "vm_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" + }, + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" + }, + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" + }, + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "lock": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "5982155361487304817" + } + }, + "definitions": { + "publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the public IP address configuration." + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the IP configuration." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" + }, + "enableTelemetry": { + "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" + }, + "ipTags": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5349747633189946992" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" + }, + "description": "Optional. The public IP address allocation method." + }, + "defaultValue": "Static" + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" + }, + "description": "Optional. IP address version." + }, + "defaultValue": "IPv4" + }, + "dnsSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" + }, + "description": "Optional. The DNS settings of the public IP address." + }, + "nullable": true + }, + "ipTags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" + }, + "description": "Optional. The list of tags associated with the public IP address." + }, + "nullable": true + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" + }, + "description": "Optional. Name of a public IP address SKU." + }, + "defaultValue": "Standard" + }, + "skuTier": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" + }, + "description": "Optional. Tier of a public IP address SKU." + }, + "defaultValue": "Regional" + }, + "ddosSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" + }, + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + }, + "nullable": true + }, + "deleteOption": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" + }, + "description": "Optional. The delete option for the public IP address." + }, + "nullable": true + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "272838238520810437" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface." + }, + "definitions": { + "networkInterfaceIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of load balancer backend address pools." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of references of LoadBalancerInboundNatRules." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the IP configuration is included." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Application Gateway Backend Address Pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The reference to gateway load balancer frontend IP." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Virtual Network Taps." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The resource ID of the deployed resource." + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backend address pool." + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application security group." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application gateway backend address pool." + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the sub resource." + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the inbound NAT rule." + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network tap." + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network interface IP configuration output." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationType" + }, + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "publicIp": { + "copy": { + "name": "publicIp", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", + "existing": true, + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", + "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", + "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", + "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", + "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", + "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", + "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", + "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2024-05-01', 'full').location]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "copy": { + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", + "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", + "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" + } + } + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the network interface." + }, + "value": "[reference('networkInterface').outputs.name.value]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "value": "[reference('networkInterface').outputs.ipConfigurations.value]" + } + } + } + } + }, + "vm_domainJoinExtension": { + "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_domainJoinExtension" + ] + }, + "vm_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] + }, + "vm_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_microsoftAntiMalwareExtension" + ] + }, + "vm_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, + "settings": { + "value": { + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "vm_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_dependencyAgentExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_networkWatcherAgentExtension" + ] + }, + "vm_customScriptExtension": { + "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" + }, + "provisionAfterExtensions": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettingsFromKeyVault": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" + }, + "settings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" + }, + "protectedSettings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "cseIdentity", + "vm" + ] + }, + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_customScriptExtension" + ] + }, + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] + }, + "vm_hostPoolRegistrationExtension": { + "condition": "[parameters('extensionHostPoolRegistration').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.PowerShell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", + "properties": { + "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", + "aadJoin": true + } + } + }, + "protectedSettings": { + "value": { + "properties": { + "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" + } + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_nvidiaGpuDriverWindowsExtension" + ] + }, + "vm_azureGuestConfigurationExtension": { + "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.GuestConfiguration" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, + "protectedSettings": { + "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_hostPoolRegistrationExtension" + ] + }, + "vm_backup": { + "condition": "[not(empty(parameters('backupVaultName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('backupVaultResourceGroup')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyId": { + "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + }, + "protectedItemType": { + "value": "Microsoft.Compute/virtualMachines" + }, + "protectionContainerName": { + "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "recoveryVaultName": { + "value": "[parameters('backupVaultName')]" + }, + "sourceResourceId": { + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17448691641471706096" + }, + "name": "Recovery Service Vaults Protection Container Protected Item", + "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "protectionContainerName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + } + }, + "recoveryVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "protectedItemType": { + "type": "string", + "allowedValues": [ + "AzureFileShareProtectedItem", + "AzureVmWorkloadSAPAseDatabase", + "AzureVmWorkloadSAPHanaDatabase", + "AzureVmWorkloadSQLDatabase", + "DPMProtectedItem", + "GenericProtectedItem", + "MabFileFolderProtectedItem", + "Microsoft.ClassicCompute/virtualMachines", + "Microsoft.Compute/virtualMachines", + "Microsoft.Sql/servers/databases" + ], + "metadata": { + "description": "Required. The backup item type." + } + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Required. ID of the backup policy with which this item is backed up." + } + }, + "sourceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource to back up." + } + } + }, + "resources": [ + { + "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", + "apiVersion": "2025-02-01", + "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "protectedItemType": "[parameters('protectedItemType')]", + "policyId": "[parameters('policyId')]", + "sourceResourceId": "[parameters('sourceResourceId')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the protected item was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the protected item." + }, + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The Name of the protected item." + }, + "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VM." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2024-07-01', 'full').location]" + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationOutputType" + }, + "metadata": { + "description": "The list of NIC configurations of the virtual machine." + }, + "copy": { + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", + "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" + } + } + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "maintenanceConfiguration", + "virtualNetwork", + "windowsVmDataCollectionRules" + ] + }, + "maintenanceConfiguration": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('mc-{0}', variables('jumpboxVmName'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionProperties": { + "value": { + "InGuestPatchMode": "User" + } + }, + "maintenanceScope": { + "value": "InGuestPatch" + }, + "maintenanceWindow": { + "value": { + "startDateTime": "2024-06-16 00:00", + "duration": "03:55", + "timeZone": "W. Europe Standard Time", + "recurEvery": "1Day" + } + }, + "visibility": { + "value": "Custom" + }, + "installPatches": { + "value": { + "rebootSetting": "IfRequired", + "windowsParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + }, + "linuxParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + } + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14895287194406877557" + }, + "name": "Maintenance Configurations", + "description": "This module deploys a Maintenance Configuration." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Maintenance Configuration Name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "extensionProperties": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" + }, + "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." + }, + "defaultValue": {} + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "maintenanceScope": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" + }, + "description": "Optional. Gets or sets maintenanceScope of the configuration." + }, + "defaultValue": "Host" + }, + "maintenanceWindow": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" + }, + "description": "Optional. Definition of a MaintenanceWindow." + }, + "defaultValue": {} + }, + "namespace": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Gets or sets namespace of the resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" + }, + "description": "Optional. Gets or sets tags of the resource." + }, + "nullable": true + }, + "visibility": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" + }, + "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." + }, + "nullable": true + }, + "installPatches": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" + }, + "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." + }, + "defaultValue": {} + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "maintenanceConfiguration": { + "type": "Microsoft.Maintenance/maintenanceConfigurations", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "extensionProperties": "[parameters('extensionProperties')]", + "maintenanceScope": "[parameters('maintenanceScope')]", + "maintenanceWindow": "[parameters('maintenanceWindow')]", + "namespace": "[parameters('namespace')]", + "visibility": "[parameters('visibility')]", + "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" + } + }, + "maintenanceConfiguration_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + }, + "maintenanceConfiguration_roleAssignments": { + "copy": { + "name": "maintenanceConfiguration_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Maintenance Configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Maintenance Configuration." + }, + "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Maintenance Configuration was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the Maintenance Configuration was created in." + }, + "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" + } + } + } + } + }, + "windowsVmDataCollectionRules": { + "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('dataCollectionRulesResourceName')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": { + "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" + }, + "dataCollectionRuleProperties": { + "value": { + "kind": "Windows", + "dataSources": { + "performanceCounters": [ + { + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Processes", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Handle Count", + "\\System\\System Up Time", + "\\System\\Context Switches/sec", + "\\System\\Processor Queue Length", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pages/sec", + "\\Memory\\Page Faults/sec", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors" + ], + "name": "perfCounterDataSource60" + } + ], + "windowsEventLogs": [ + { + "name": "SecurityAuditEvents", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" + ] + } + ] + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", + "name": "[variables('dcrLogAnalyticsDestinationName')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Microsoft-Perf" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Perf" + }, + { + "streams": [ + "Microsoft-Event" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Event" + } + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2441324888126124697" + }, + "name": "Data Collection Rules", + "description": "This module deploys a Data Collection Rule." + }, + "definitions": { + "dataCollectionRulePropertiesType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Linux": { + "$ref": "#/definitions/linuxDcrPropertiesType" + }, + "Windows": { + "$ref": "#/definitions/windowsDcrPropertiesType" + }, + "All": { + "$ref": "#/definitions/allPlatformsDcrPropertiesType" + }, + "AgentSettings": { + "$ref": "#/definitions/agentSettingsDcrPropertiesType" + }, + "Direct": { + "$ref": "#/definitions/directDcrPropertiesType" + }, + "WorkspaceTransforms": { + "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" + }, + "PlatformTelemetry": { + "$ref": "#/definitions/platformTelemetryDcrPropertiesType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." + } + }, + "linuxDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Linux" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Linux' data collection rule." + } + }, + "windowsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Windows" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Windows' data collection rule." + } + }, + "allPlatformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the data collection rule of the kind 'All'." + } + }, + "agentSettingsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AgentSettings" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "agentSettings": { + "$ref": "#/definitions/agentSettingsType", + "metadata": { + "description": "Required. Agent settings used to modify agent behavior on a given host." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'AgentSettings' data collection rule." + } + }, + "agentSettingsType": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agentSettingType" + }, + "metadata": { + "description": "Required. All the settings that are applicable to the logs agent (AMA)." + } + } + }, + "metadata": { + "description": "The type for the agent settings." + } + }, + "agentSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "MaxDiskQuotaInMB", + "UseTimeReceivedForForwardedEvents" + ], + "metadata": { + "description": "Required. The name of the agent setting." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the agent setting." + } + } + }, + "metadata": { + "description": "The type for the (single) agent setting." + } + }, + "directDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Direct" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Required. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Direct' data collection rule." + } + }, + "workspaceTransformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "WorkspaceTransforms" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." + } + }, + "platformTelemetryDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "PlatformTelemetry" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "dataSources": { + "type": "object", + "properties": { + "platformTelemetry": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + }, + "description": "Required. The list of platform telemetry configurations." + } + } + }, + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "destinations": { + "type": "object", + "properties": { + "logAnalytics": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + }, + "description": "Optional. The list of Log Analytics destinations." + }, + "nullable": true + }, + "storageAccounts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + }, + "description": "Optional. The list of Storage Account destinations." + }, + "nullable": true + }, + "eventHubs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + }, + "description": "Optional. The list of Event Hub destinations." + }, + "nullable": true + } + }, + "metadata": { + "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the data collection rule. The name is case insensitive." + } + }, + "dataCollectionRuleProperties": { + "$ref": "#/definitions/dataCollectionRulePropertiesType", + "metadata": { + "description": "Required. The kind of data collection rule." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dataCollectionRule": { + "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('dataCollectionRuleProperties').kind]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRuleAll": { + "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRule_conditionalScopeLock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", + "lock": { + "value": "[parameters('lock')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2876136109547890997" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "dataCollectionRuleName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + } + } + }, + "resources": { + "dataCollectionRule": { + "existing": true, + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dataCollectionRuleName')]" + }, + "dataCollectionRule_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + }, + "dataCollectionRule_roleAssignments": { + "copy": { + "name": "dataCollectionRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", + "name": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14634305923902101494" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource." + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dataCollectionRule was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" + }, + "endpoints": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", + "output": true + }, + "description": "The endpoints of the dataCollectionRule, if created." + }, + "nullable": true, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" + }, + "immutableId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The ImmutableId of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "avmPrivateDnsZones": { + "copy": { + "name": "avmPrivateDnsZones", + "count": "[length(variables('privateDnsZones'))]", + "mode": "serial", + "batchSize": 5 + }, + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZones')[copyIndex()]]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "virtualNetworkLinks": { + "value": [ + { + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18337341331267624582" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone." + }, + "definitions": { + "aType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the A record." + } + }, + "aaaaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aaaaRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" + }, + "description": "Optional. The list of AAAA records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the AAAA record." + } + }, + "cnameType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. The CNAME record in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the CNAME record." + } + }, + "mxType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the MX record." + } + }, + "ptrType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the PTR record." + } + }, + "soaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. The SOA record in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SOA record." + } + }, + "srvType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "srvRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SRV record." + } + }, + "txtType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the TXT record." + } + }, + "virtualNetworkLinkType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Optional. The resource name." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the virtual network to link." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Region where the resource lives." + } + }, + "registrationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "resolutionPolicy": { + "type": "string", + "allowedValues": [ + "Default", + "NxDomainRedirect" + ], + "nullable": true, + "metadata": { + "description": "Optional. The resolution type of the private-dns-zone fallback machanism." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network link." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "a": { + "type": "array", + "items": { + "$ref": "#/definitions/aType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of A records." + } + }, + "aaaa": { + "type": "array", + "items": { + "$ref": "#/definitions/aaaaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of AAAA records." + } + }, + "cname": { + "type": "array", + "items": { + "$ref": "#/definitions/cnameType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of CNAME records." + } + }, + "mx": { + "type": "array", + "items": { + "$ref": "#/definitions/mxType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of MX records." + } + }, + "ptr": { + "type": "array", + "items": { + "$ref": "#/definitions/ptrType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of PTR records." + } + }, + "soa": { + "type": "array", + "items": { + "$ref": "#/definitions/soaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SOA records." + } + }, + "srv": { + "type": "array", + "items": { + "$ref": "#/definitions/srvType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SRV records." + } + }, + "txt": { + "type": "array", + "items": { + "$ref": "#/definitions/txtType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of TXT records." + } + }, + "virtualNetworkLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkLinkType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_roleAssignments": { + "copy": { + "name": "privateDnsZone_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_A": { + "copy": { + "name": "privateDnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" + }, + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7372385900111002873" + }, + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the A record." + } + }, + "aRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed A record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed A record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed A record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_AAAA": { + "copy": { + "name": "privateDnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" + }, + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14405855828972373002" + }, + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the AAAA record." + } + }, + "aaaaRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" + }, + "description": "Optional. The list of AAAA records in the record set." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AAAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed AAAA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed AAAA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_CNAME": { + "copy": { + "name": "privateDnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" + }, + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13818627461335065928" + }, + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CNAME record." + } + }, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. A CNAME record." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CNAME record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CNAME record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CNAME record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_MX": { + "copy": { + "name": "privateDnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" + }, + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2977624679479439942" + }, + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_PTR": { + "copy": { + "name": "privateDnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + }, + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15286275176817336979" + }, + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PTR record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SOA": { + "copy": { + "name": "privateDnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" + }, + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4837447718856535826" + }, + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. A SOA record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SRV": { + "copy": { + "name": "privateDnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15028912535488490265" + }, + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "srvRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_TXT": { + "copy": { + "name": "privateDnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" + }, + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7641583415110009849" + }, + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7392770862892927923" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "logAnalyticsWorkspace": { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('logAnalyticsWorkspaceResourceName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableReplication": { + "value": "[parameters('enableRedundancy')]" + }, + "replicationLocation": { + "value": "[variables('replicaLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9919485194443011422" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days. WAF recommends 365." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "metadata": { + "description": "SKU name for the workspace." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access for ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access for query." + } + }, + "enableReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable workspace replication for redundancy." + } + }, + "replicationLocation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Replication location (paired region)." + } + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Data sources for VM monitoring (Windows events, perf counters)." + } + } + }, + "resources": { + "workspace": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": "[parameters('retentionInDays')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "diagnosticSettings": { + "value": [ + { + "useThisWorkspace": true + } + ] + }, + "publicNetworkAccessForIngestion": { + "value": "[parameters('publicNetworkAccessForIngestion')]" + }, + "publicNetworkAccessForQuery": { + "value": "[parameters('publicNetworkAccessForQuery')]" + }, + "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", + "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", + "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14099489006827800075" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace." + }, + "definitions": { + "diagnosticSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "gallerySolutionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the gallery solutions to be created in the log analytics workspace." + } + }, + "storageInsightsConfigType": { + "type": "object", + "properties": { + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the storage account to be linked." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of tables to be read by the workspace." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the storage insights configuration." + } + }, + "linkedServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked service." + } + }, + "linkedStorageAccountType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked storage account." + } + }, + "savedSearchType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "etag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. The category of the saved search. This helps the user to find a saved search faster." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "functionAlias": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. The query expression for the saved search." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The tags attached to the saved search." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language. The current version is 2 and is the default." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the saved search." + } + }, + "dataExportType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data export." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. The destination of the data export." + } + }, + "enable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the data export." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of table names to export." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data export." + } + }, + "dataSourceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "metadata": { + "description": "Required. The kind of data source." + } + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the event log to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data source." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "plan": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The plan for the table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. The restored logs for the table." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. The schema for the table." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. The search results for the table." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The role assignments for the table." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the custom table." + } + }, + "workspaceFeaturesType": { + "type": "object", + "properties": { + "disableLocalAuth": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable Non-EntraID based Auth. Default is true." + } + }, + "enableDataExport": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that indicate if data should be exported." + } + }, + "enableLogAccessUsingOnlyResourcePermissions": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable log access using only resource permissions. Default is false." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that describes if we want to remove the data after 30 days." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Features of the workspace." + } + }, + "workspaceReplicationType": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Replication properties of the workspace." + } + }, + "_1.columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "description": "The parameters of the table column.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "description": "The data export destination properties.", + "__bicep_imported_from!": { + "sourceTemplate": "data-export/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the restore operation that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "description": "The table schema.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the search job that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/storageInsightsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "linkedServices": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedStorageAccountType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + } + }, + "savedSearches": { + "type": "array", + "items": { + "$ref": "#/definitions/savedSearchType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "items": { + "$ref": "#/definitions/dataExportType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "items": { + "$ref": "#/definitions/dataSourceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." + } + }, + "onboardWorkspaceToSentinel": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "-1", + "metadata": { + "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." + } + }, + "defaultDataCollectionRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "features": { + "$ref": "#/definitions/workspaceFeaturesType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace features." + } + }, + "replication": { + "$ref": "#/definitions/workspaceReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace replication properties." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", + "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", + "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", + "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]", + "replication": "[parameters('replication')]", + "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" + }, + "identity": "[variables('identity')]" + }, + "logAnalyticsWorkspace_diagnosticSettings": { + "copy": { + "name": "logAnalyticsWorkspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_sentinelOnboarding": { + "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", + "type": "Microsoft.SecurityInsights/onboardingStates", + "apiVersion": "2025-09-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "default", + "properties": {}, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { + "copy": { + "name": "logAnalyticsWorkspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "140290971998938797" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14482465616812596213" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedStorageAccounts": { + "copy": { + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" + }, + "storageAccountIds": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14864721709229272590" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": "[parameters('storageAccountIds')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" + }, + "etag": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + }, + "category": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" + }, + "query": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17904092372918022238" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] + }, + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17943947755417749524" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_dataSources": { + "copy": { + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" + }, + "kind": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "15360290236166491819" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "18383178824663161801" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10255889523646649592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" + }, + "primarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The primary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" + }, + "secondarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The secondary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.name.value]" + }, + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." + }, + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + } + }, + "applicationInsights": { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appi-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "retentionInDays": { + "value": 365 + }, + "kind": { + "value": "web" + }, + "disableIpMasking": { + "value": false + }, + "flowType": { + "value": "Bluefield" + }, + "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17358780145253914698" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "flowType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." + } + }, + "requestSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Purge data immediately after 30 days." + } + }, + "ingestionMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ApplicationInsights", + "ApplicationInsightsWithDiagnosticSettings", + "LogAnalytics" + ], + "metadata": { + "description": "Optional. Indicates the flow of the ingestion." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/components@2020-02-02#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]", + "Flow_Type": "[parameters('flowType')]", + "Request_Source": "[parameters('requestSource')]", + "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", + "IngestionMode": "[parameters('ingestionMode')]" + } + }, + "appInsights_roleAssignments": { + "copy": { + "name": "appInsights_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_diagnosticSettings": { + "copy": { + "name": "appInsights_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5059808225314360251" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "appInsights" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights component was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference('appInsights').AppId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "avmManagedIdentity": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('identityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + "avmContainerRegistry": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "acrPullPrincipalIds": { + "value": [ + "[reference('avmContainerRegistryReader').outputs.principalId.value]" + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8138805991948000285" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user for the registry." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." + } + }, + "acrPullPrincipalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Principal IDs to assign AcrPull role." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable private networking." + } + }, + "privateEndpointSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for private endpoint." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Private DNS zone resource IDs for private endpoint." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Azure telemetry collection." + } + } + }, + "variables": { + "copy": [ + { + "name": "roleAssignments", + "count": "[length(parameters('acrPullPrincipalIds'))]", + "input": { + "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", + "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", + "principalType": "ServicePrincipal" + } + }, + { + "name": "dnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" + } + } + ], + "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "acrSku": { + "value": "[parameters('sku')]" + }, + "acrAdminUserEnabled": { + "value": "[parameters('adminUserEnabled')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "exportPolicyStatus": { + "value": "[parameters('exportPolicyStatus')]" + }, + "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[variables('privateEndpointConfig')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1509121545318808417" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR)." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "credentialSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a credential set." + } + }, + "scopeMapsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" + }, + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a scope map." + } + }, + "cacheRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cache rule." + } + }, + "replicationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" + }, + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replication." + } + }, + "taskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties for the task." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The step properties for the task." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The trigger properties for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the task at the time the operation was called." + }, + "nullable": true + }, + "timeout": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The agent configuration for the task." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." + } + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The log template for the task to use when creating logs in Log Analytics." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a task." + } + }, + "tokenType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map which defines the permissions for this token." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" + }, + "description": "Optional. The status of the token at the time the operation was called." + }, + "nullable": true + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." + } + } + } + }, + "webhookType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the webhook at the time the operation was called." + }, + "nullable": true + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + }, + "description": "Optional. Custom headers that will be added to the webhook notifications." + }, + "nullable": true + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a webhook." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "description": "The type for auth credentials.", + "__bicep_imported_from!": { + "sourceTemplate": "credential-set/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "autoGeneratedDomainNameLabelScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse", + "Unsecure" + ], + "metadata": { + "description": "Optional. The domain name label reuse scope." + } + }, + "roleAssignmentMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AbacRepositoryPermissions", + "LegacyRegistryPermissions" + ], + "metadata": { + "description": "Optional. The registry permissions role assignment mode." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "items": { + "$ref": "#/definitions/replicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/webhookType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "items": { + "$ref": "#/definitions/cacheRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialSetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/scopeMapsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Scope maps setting." + } + }, + "tokens": { + "type": "array", + "items": { + "$ref": "#/definitions/tokenType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tokens to create for the container registry." + } + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/definitions/taskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of ACR Tasks to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", + "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", + "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", + "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", + "roleAssignmentMode": "[parameters('roleAssignmentMode')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "registry_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3787322352564227867" + }, + "name": "Container Registries scope maps", + "description": "This module deploys an Azure Container Registry (ACR) scope map." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6219097750044645017" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13412699468141336519" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set." + }, + "definitions": { + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for auth credentials." + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1319901650921923538" + }, + "name": "Container Registry Cache", + "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "cacheRule": { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_tokens": { + "copy": { + "name": "registry_tokens", + "count": "[length(coalesce(parameters('tokens'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "scopeMapResourceId": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5970335582661416899" + }, + "name": "Container Registries Tokens", + "description": "Deploys an Azure Container Registry (ACR) Token." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map to which the token will be associated with." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the token. Default is enabled." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + }, + "description": "Optional. The credentials associated with the token for authentication." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "token": { + "type": "Microsoft.ContainerRegistry/registries/tokens", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "scopeMapId": "[parameters('scopeMapResourceId')]", + "status": "[parameters('status')]", + "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the token." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the token was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the token." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_scopeMaps" + ] + }, + "registry_tasks": { + "copy": { + "name": "registry_tasks", + "count": "[length(coalesce(parameters('tasks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "platform": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" + }, + "step": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" + }, + "trigger": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" + }, + "timeout": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" + }, + "agentConfiguration": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" + }, + "agentPoolName": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" + }, + "isSystemTask": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" + }, + "logTemplate": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2468771835002458415" + }, + "name": "Container Registries Tasks", + "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." + }, + "definitions": { + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties against which the task has to run." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The properties that describe all triggers for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. The current status of task." + } + }, + "timeout": { + "type": "int", + "defaultValue": 3600, + "minValue": 300, + "maxValue": 28800, + "metadata": { + "description": "Optional. Run timeout in seconds." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The machine configuration of the run agent." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The dedicated agent pool for the task." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" + }, + "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + }, + "nullable": true + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The value of this property indicates whether the task resource is system task or not." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The template that describes the repository and tag information for run log artifact." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "task": { + "type": "Microsoft.ContainerRegistry/registries/tasks", + "apiVersion": "2025-03-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "agentConfiguration": "[parameters('agentConfiguration')]", + "agentPoolName": "[parameters('agentPoolName')]", + "credentials": "[parameters('credentials')]", + "isSystemTask": "[parameters('isSystemTask')]", + "logTemplate": "[parameters('logTemplate')]", + "platform": "[parameters('platform')]", + "status": "[parameters('status')]", + "step": "[parameters('step')]", + "timeout": "[parameters('timeout')]", + "trigger": "[parameters('trigger')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the task." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the task was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the task." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('task', '2025-03-01-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3200175097987099858" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "securestring", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_replications" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference('registry').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2025-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Azure container registry." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "avmContainerRegistryReader", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", + "virtualNetwork" + ] + }, + "avmStorageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "minimumTlsVersion": { + "value": "TLS1_2" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", + "ipRules": [] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "supportsHttpsTrafficOnly": { + "value": true + }, + "accessTier": { + "value": "Hot" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1254456195180100771" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoints output." + } + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network configuration." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey1 secret name to create." + } + }, + "connectionString1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString1 secret name to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey2 secret name to create." + } + }, + "connectionString2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString2 secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the exported secrets." + } + }, + "localUserType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a local user." + } + }, + "blobServiceType": { + "type": "object", + "properties": { + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/blobCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "versionDeletePolicyDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a blob service." + } + }, + "fileServiceType": { + "type": "object", + "properties": { + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." + }, + "nullable": true + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "nullable": true + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/fileCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a file service." + } + }, + "queueServiceType": { + "type": "object", + "properties": { + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/queueCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a queue service." + } + }, + "tableServiceType": { + "type": "object", + "properties": { + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/tableCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a table service." + } + }, + "objectReplicationPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." + } + }, + "destinationStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the destination storage account." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. The storage account object replication rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy." + } + }, + "_1.immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/container/main.bicep" + } + } + }, + "_2.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "blobCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/_1.immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type of a storage container.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "fileCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a file share.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "object-replication-policy/policy/main.bicep" + } + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "queueCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a queue.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_2.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "tableCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a table.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "extendedLocationZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS", + "Standard_GRS", + "Standard_GZRS", + "Standard_RAGRS", + "Standard_RAGZRS", + "StandardV2_LRS", + "StandardV2_ZRS", + "StandardV2_GRS", + "StandardV2_GZRS", + "Premium_LRS", + "Premium_ZRS", + "PremiumV2_LRS", + "PremiumV2_ZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "Cold" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" + }, + "description": "Optional. Provides the identity based authentication settings for Azure Files." + }, + "nullable": true + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Optional. The Storage Account ManagementPolicies Rules." + }, + "nullable": true + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "$ref": "#/definitions/blobServiceType", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "$ref": "#/definitions/fileServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "$ref": "#/definitions/queueServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "$ref": "#/definitions/tableServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_2", + "TLS1_3" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/localUserType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "sasExpirationAction": { + "type": "string", + "defaultValue": "Log", + "allowedValues": [ + "Block", + "Log" + ], + "metadata": { + "description": "Optional. The SAS expiration action. Allowed values are Block and Log." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "immutableStorageWithVersioning": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" + }, + "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." + }, + "nullable": true + }, + "objectReplicationPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Object replication policies for the storage account." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2025-05-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[variables('formattedManagementPolicies')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4000605059554016072" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Required. The Storage Account ManagementPolicies Rules." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + }, + "storageAccount_localUsers": { + "copy": { + "name": "storageAccount_localUsers", + "count": "[length(coalesce(parameters('localUsers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1801226901235196767" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "468225492069709453" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a storage container." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "container/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false, + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[parameters('defaultServiceVersion')]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "273904034769611992" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an immutability policy." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "defaultValue": {} + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "container_immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15304742179563677019" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "blobServices" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + }, + "corsRules": { + "value": "[tryGet(parameters('fileServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17583198711200998285" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a file share." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." + }, + "defaultValue": {} + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "defaultValue": { + "enabled": true, + "days": 7 + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "provisionedBandwidthMibps": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + }, + "provisionedIops": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10353179772982843397" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]", + "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", + "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + }, + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9644461291744477521" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a queue." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "12812824360066955039" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair that represents queue metadata." + }, + "defaultValue": {} + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" + }, + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + }, + "corsRules": { + "value": "[tryGet(parameters('tableServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10320403358700650147" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11362260974696477885" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13227497656004178962" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_objectReplicationPolicies": { + "copy": { + "name": "storageAccount_objectReplicationPolicies", + "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "destinationAccountResourceId": { + "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" + }, + "enableMetrics": { + "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" + }, + "rules": { + "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1894366578172550759" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "policy/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the parent Storage Account." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "variables": { + "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", + "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", + "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", + "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "destinationPolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", + "subscriptionId": "[variables('destAccountSubscription')]", + "resourceGroup": "[variables('destAccountResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('name'), 'default')]" + }, + "storageAccountName": { + "value": "[variables('destAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "value": "[parameters('rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } + } + } + } + }, + "sourcePolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[reference('destinationPolicy').outputs.policyId.value]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('rules'))]", + "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } + } + } + }, + "dependsOn": [ + "destinationPolicy" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.policyId.value]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2025-06-01', 'full').location]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." + }, + "value": "[reference('storageAccount').primaryEndpoints]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Storage Account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The primary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + }, + "secondaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The secondary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" + }, + "primaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" + }, + "secondaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", + "virtualNetwork" + ] + }, + "avmAiServices": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "projectName": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "projectDescription": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "existingFoundryProjectResourceId": { + "value": "[variables('existingProjectResourceId')]" + }, + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "sku": { + "value": "S0" + }, + "allowProjectManagement": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "kind": { + "value": "AIServices" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('azureAiServiceLocation')]" + } + }, + "customSubDomainName": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" + } + }, + "disableLocalAuth": { + "value": true + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "deployments": { + "value": [ + { + "name": "[parameters('gptModelName')]", + "model": { + "format": "OpenAI", + "name": "[parameters('gptModelName')]", + "version": "[parameters('gptModelVersion')]" + }, + "sku": { + "name": "[parameters('deploymentType')]", + "capacity": "[parameters('gptDeploymentCapacity')]" + }, + "raiPolicyName": "Microsoft.Default" + } + ] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18336251851332975005" + }, + "name": "Cognitive Services", + "description": "This module deploys a Cognitive Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/project.bicep" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "" + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "allowProjectManagement": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable project management feature for AI Foundry." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", + "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2025-01-31-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "cognitiveServiceNew": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "allowProjectManagement": "[parameters('allowProjectManagement')]", + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "cognitiveServiceExisting": { + "condition": "[variables('useExistingService')]", + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "cognitive_service_dependencies": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + } + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + } + }, + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } + }, + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + } + } + } + }, + "dependsOn": [ + "cognitiveServiceNew" + ] + }, + "existing_cognitive_service_dependencies": { + "condition": "[variables('useExistingService')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + } + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + } + }, + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } + }, + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The service endpoint of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" + }, + "endpoints": { + "$ref": "#/definitions/endpointType", + "metadata": { + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "logAnalyticsWorkspace" + ] + }, + "cognitiveServicePrivateEndpoint": { + "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": { + "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", + "properties": { + "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", + "groupIds": [ + "account" + ] + } + } + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "name": "ai-services-dns-zone-cognitiveservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-openai", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-aiservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-contentunderstanding", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" + } + ] + } + }, + "subnetResourceId": { + "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "avmAiServices", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", + "virtualNetwork" + ] + }, + "avmContainerAppEnv": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('cae-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", + "workloadProfiles": { + "value": [ + { + "name": "Consumption", + "workloadProfileType": "Consumption" + } + ] + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "platformReservedCidr": { + "value": "172.17.17.0/24" + }, + "platformReservedDnsIP": { + "value": "172.17.17.17" + }, + "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", + "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11924518395502120940" + }, + "name": "App ManagedEnvironments", + "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." + }, + "definitions": { + "certificateType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the certificate." + } + }, + "certificateType": { + "type": "string", + "allowedValues": [ + "ImagePullTrustedCA", + "ServerSSLCertificate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location for the resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a certificate." + } + }, + "storageType": { + "type": "object", + "properties": { + "accessMode": { + "type": "string", + "allowedValues": [ + "ReadOnly", + "ReadWrite" + ], + "metadata": { + "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. File share name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the storage." + } + }, + "appLogsConfigurationType": { + "type": "object", + "discriminator": { + "propertyName": "destination", + "mapping": { + "azure-monitor": { + "$ref": "#/definitions/appLogsConfigurationMonitorType" + }, + "log-analytics": { + "$ref": "#/definitions/appLogsConfigurationLawType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the App Logs Configuration." + } + }, + "appLogsConfigurationMonitorType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "azure-monitor" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using azure-monitor." + } + }, + "appLogsConfigurationLawType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "log-analytics" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Existing Log Analytics Workspace resource ID." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using log-analytics." + } + }, + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } + }, + "metadata": { + "description": "The type for the certificate's key vault properties.", + "__bicep_imported_from!": { + "sourceTemplate": "certificate/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string." + } + }, + "daprConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" + }, + "description": "Optional. The configuration of Dapr component." + }, + "nullable": true + }, + "ingressConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" + }, + "description": "Optional. Ingress configuration for the Managed Environment." + }, + "nullable": true + }, + "kedaConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" + }, + "description": "Optional. The configuration of Keda component." + }, + "nullable": true + }, + "peerAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" + }, + "description": "Optional. Peer authentication settings for the Managed Environment." + }, + "nullable": true + }, + "daprAIConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." + } + }, + "daprAIInstrumentationKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." + } + }, + "dockerBridgeCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "infrastructureSubnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "internal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedDnsIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "peerTrafficEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not to encrypt peer traffic." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether to allow or block all public traffic." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not this Managed Environment is zone-redundant." + } + }, + "certificatePassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Password of the certificate used by the custom domain." + } + }, + "certificateValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Certificate to use for the custom domain. PFX or PEM." + } + }, + "dnsSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. DNS suffix for the environment domain." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "openTelemetryConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" + }, + "description": "Optional. Open Telemetry configuration." + }, + "nullable": true + }, + "workloadProfiles": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" + }, + "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." + }, + "nullable": true + }, + "infrastructureResourceGroupName": { + "type": "string", + "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", + "metadata": { + "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "storages": { + "type": "array", + "items": { + "$ref": "#/definitions/storageType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of storages to mount on the environment." + } + }, + "certificate": { + "$ref": "#/definitions/certificateType", + "nullable": true, + "metadata": { + "description": "Optional. A Managed Environment Certificate." + } + }, + "appLogsConfiguration": { + "$ref": "#/definitions/appLogsConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The AppLogsConfiguration for the Managed Environment." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-11-01", + "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-02-01", + "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" + }, + "managedEnvironment": { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "appInsightsConfiguration": { + "connectionString": "[parameters('appInsightsConnectionString')]" + }, + "daprConfiguration": "[parameters('daprConfiguration')]", + "ingressConfiguration": "[parameters('ingressConfiguration')]", + "kedaConfiguration": "[parameters('kedaConfiguration')]", + "peerAuthentication": "[parameters('peerAuthentication')]", + "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", + "daprAIConnectionString": "[parameters('daprAIConnectionString')]", + "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", + "customDomainConfiguration": { + "certificatePassword": "[parameters('certificatePassword')]", + "certificateValue": "[parameters('certificateValue')]", + "dnsSuffix": "[parameters('dnsSuffix')]", + "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" + }, + "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", + "peerTrafficConfiguration": { + "encryption": { + "enabled": "[parameters('peerTrafficEncryption')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "vnetConfiguration": { + "internal": "[parameters('internal')]", + "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", + "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", + "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", + "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" + }, + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]", + "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "managedEnvironment_roleAssignments": { + "copy": { + "name": "managedEnvironment_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_storage": { + "copy": { + "name": "managedEnvironment_storage", + "count": "[length(coalesce(parameters('storages'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" + }, + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "kind": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + }, + "accessMode": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + }, + "storageAccountName": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "945327737463253676" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "managedEnvironmentName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "accessMode": { + "type": "string", + "metadata": { + "description": "Required. The access mode for the storage." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "storage": { + "type": "Microsoft.App/managedEnvironments/storages", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "properties": { + "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", + "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the file share." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the file share was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_certificate": { + "condition": "[not(empty(parameters('certificate')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" + }, + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "certificateKeyVaultProperties": { + "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" + }, + "certificateType": { + "value": "[tryGet(parameters('certificate'), 'certificateType')]" + }, + "certificateValue": { + "value": "[tryGet(parameters('certificate'), 'certificateValue')]" + }, + "certificatePassword": { + "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" + }, + "location": { + "value": "[tryGet(parameters('certificate'), 'location')]" + }, + "tags": { + "value": "[tryGet(parameters('certificate'), 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "574133184207535827" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "definitions": { + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the certificate's key vault properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment Certificate." + } + }, + "managedEnvironmentName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference to the certificate to use for the custom domain." + } + }, + "certificateType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ServerSSLCertificate", + "ImagePullTrustedCA" + ], + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "managedEnvironmentCertificate": { + "type": "Microsoft.App/managedEnvironments/certificates", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", + "certificateType": "[parameters('certificateType')]", + "password": "[parameters('certificatePassword')]", + "value": "[parameters('certificateValue')]" + }, + "tags": "[parameters('tags')]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the certificate was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedEnvironment" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Managed Environment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Managed Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Managed Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('managedEnvironment').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The IP address of the Managed Environment." + }, + "value": "[reference('managedEnvironment').staticIp]" + }, + "domainVerificationId": { + "type": "string", + "metadata": { + "description": "The domain verification id for custom domains." + }, + "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "virtualNetwork" + ] + }, + "avmContainerRegistryReader": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } + } + } + } + }, + "avmContainerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_API": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_Web": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 3000 + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_API_BASE_URL", + "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" + }, + { + "name": "APP_WEB_CLIENT_ID", + "value": "" + }, + { + "name": "APP_WEB_AUTHORITY", + "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" + }, + { + "name": "APP_WEB_SCOPE", + "value": "" + }, + { + "name": "APP_API_SCOPE", + "value": "" + }, + { + "name": "APP_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_POST_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_CONSOLE_LOG_ENABLED", + "value": "false" + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp_API", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_Workflow": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmCosmosDB": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "mongodbDatabases": { + "value": [ + { + "name": "default", + "tag": "default database" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "databaseAccountOfferType": { + "value": "Standard" + }, + "enableAutomaticFailover": { + "value": false + }, + "serverVersion": { + "value": "7.0" + }, + "capabilitiesToAdd": { + "value": [ + "EnableMongo" + ] + }, + "defaultConsistencyLevel": { + "value": "Session" + }, + "maxIntervalInSeconds": { + "value": 5 + }, + "maxStalenessPrefix": { + "value": 100 + }, + "zoneRedundant": { + "value": false + }, + "networkRestrictions": { + "value": { + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", + "ipRules": [], + "virtualNetworkRules": [] + } + }, + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1772014800591596213" + }, + "name": "Azure Cosmos DB account", + "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group ID for the private endpoint group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses for the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "failoverLocationType": { + "type": "object", + "properties": { + "failoverPriority": { + "type": "int", + "metadata": { + "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." + } + }, + "isZoneRedundant": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." + } + }, + "locationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the region." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the failover location." + } + }, + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." + } + }, + "sqlRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/nestedSqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." + } + }, + "networkRestrictionType": { + "type": "object", + "properties": { + "ipRules": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." + } + }, + "networkAclBypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." + } + }, + "publicNetworkAccess": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." + } + }, + "virtualNetworkRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of a subnet." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." + } + }, + "networkAclBypassResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network restriction." + } + }, + "gremlinDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a gremlin databae." + } + }, + "mongoDbType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a mongo databae." + } + }, + "sqlDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a sql database." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "cassandraStandaloneRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." + } + }, + "cassandraRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "cassandraKeyspaceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraTableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraViewType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB Cassandra keyspace." + } + }, + "defaultIdentityType": { + "type": "object", + "discriminator": { + "propertyName": "name", + "mapping": { + "FirstPartyIdentity": { + "$ref": "#/definitions/defaultIdentityFirstPartyType" + }, + "SystemAssignedIdentity": { + "$ref": "#/definitions/defaultIdentitySystemAssignedType" + }, + "UserAssignedIdentity": { + "$ref": "#/definitions/defaultIdentityUserAssignedType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the default identity." + } + }, + "defaultIdentityFirstPartyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "FirstPartyIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentitySystemAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "SystemAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentityUserAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "UserAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the user assigned identity to use as the default identity." + } + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-role-definition/main.bicep" + } + } + }, + "cassandraTableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "description": "The type of a Cassandra table.", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "tableType" + } + } + }, + "cassandraViewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "description": "The type of a Cassandra view (materialized view).", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "viewType" + } + } + }, + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "description": "The type of a collection.", + "__bicep_imported_from!": { + "sourceTemplate": "mongodb-database/main.bicep" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "description": "The type of a container.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-database/main.bicep" + } + } + }, + "customerManagedKeyAndVaultOnlyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "description": "The type of a graph.", + "__bicep_imported_from!": { + "sourceTemplate": "gremlin-database/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "nestedSqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "description": "The type for the SQL Role Assignments.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-role-definition/main.bicep", + "originalIdentifier": "sqlRoleAssignmentType" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the account." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Defaults to the current resource group scope location. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "databaseAccountOfferType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], + "metadata": { + "description": "Optional. The offer type for the account. Defaults to \"Standard\"." + } + }, + "failoverLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/failoverLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." + } + }, + "defaultConsistencyLevel": { + "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], + "metadata": { + "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." + } + }, + "disableLocalAuthentication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." + } + }, + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." + } + }, + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions. Defaults to true." + } + }, + "enableFreeTier": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." + } + }, + "enableMultipleWriteLocations": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." + } + }, + "disableKeyBasedMetadataWriteAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." + } + }, + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." + } + }, + "serverVersion": { + "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2", + "5.0", + "6.0", + "7.0" + ], + "metadata": { + "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." + } + }, + "sqlDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." + } + }, + "mongodbDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/mongoDbType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." + } + }, + "gremlinDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/gremlinDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." + } + }, + "cassandraKeyspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraKeyspaceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "totalThroughputLimit": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of control plane Azure role-based access control assignments." + } + }, + "sqlRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." + } + }, + "cassandraRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings for the service." + } + }, + "capabilitiesToAdd": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless", + "EnableNoSQLVectorSearch", + "EnableNoSQLFullTextSearch", + "EnableMaterializedViews", + "DeleteAllItemsByPartitionKey" + ], + "metadata": { + "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." + } + }, + "backupPolicyType": { + "type": "string", + "defaultValue": "Continuous", + "allowedValues": [ + "Periodic", + "Continuous" + ], + "metadata": { + "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." + } + }, + "backupPolicyContinuousTier": { + "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], + "metadata": { + "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." + } + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." + } + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, + "metadata": { + "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." + } + }, + "backupStorageRedundancy": { + "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], + "metadata": { + "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." + } + }, + "networkRestrictions": { + "$ref": "#/definitions/networkRestrictionType", + "defaultValue": { + "ipRules": [], + "virtualNetworkRules": [], + "publicNetworkAccess": "Disabled" + }, + "metadata": { + "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "Tls12", + "allowedValues": [ + "Tls12" + ], + "metadata": { + "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." + } + }, + "enableBurstCapacity": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." + } + }, + "enableCassandraConnector": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." + } + }, + "enablePartitionMerge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." + } + }, + "enablePerRegionPerPartitionAutoscale": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." + } + }, + "analyticalStorageConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" + }, + "description": "Optional. Analytical storage specific properties." + }, + "nullable": true + }, + "cors": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" + }, + "description": "Optional. The CORS policy for the Cosmos DB database account." + }, + "nullable": true + }, + "defaultIdentity": { + "$ref": "#/definitions/defaultIdentityType", + "defaultValue": { + "name": "FirstPartyIdentity" + }, + "metadata": { + "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInControlPlaneRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" + }, + "databaseAccount": { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", + "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", + "dependsOn": [ + "cMKKeyVault::cMKKey" + ] + }, + "databaseAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_diagnosticSettings": { + "copy": { + "name": "databaseAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_roleAssignments": { + "copy": { + "name": "databaseAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlDatabases": { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "3972888645334640168" + }, + "name": "DocumentDB Database Account SQL Databases", + "description": "This module deploys a SQL Database in a CosmosDB Account." + }, + "definitions": { + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a container." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "container": { + "copy": { + "name": "container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "conflictResolutionPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + }, + "defaultTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "kind": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + }, + "paths": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + }, + "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", + "uniqueKeyPolicyKeys": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "4781880351108045502" + }, + "name": "DocumentDB Database Account SQL Database Containers", + "description": "This module deploys a SQL Database Container in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "variables": { + "copy": [ + { + "name": "partitionKeyPaths", + "count": "[length(parameters('paths'))]", + "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + } + ] + }, + "resources": { + "databaseAccount::sqlDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "container": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlRoleDefinitions": { + "copy": { + "name": "databaseAccount_sqlRoleDefinitions", + "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "dataActions": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" + }, + "roleName": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "sqlRoleAssignments": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "8514367433037227852" + }, + "name": "DocumentDB Database Account SQL Role Definitions.", + "description": "This module deploys a SQL Role Definision in a CosmosDB Account." + }, + "definitions": { + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SQL Role Assignments." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionIdOrName": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The role name of the SQL Role Definition." + }, + "value": "[reference('sqlRoleDefinition').roleName]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionIdOrName": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_sqlDatabases", + "databaseAccount_sqlRoleDefinitions" + ] + }, + "databaseAccount_cassandraRoleDefinitions": { + "copy": { + "name": "databaseAccount_cassandraRoleDefinitions", + "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "roleName": { + "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "dataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" + }, + "notDataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "cassandraRoleAssignments": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10787709019875067397" + }, + "name": "DocumentDB Database Account Cassandra Role Definitions.", + "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." + }, + "definitions": { + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]", + "notDataActions": "[parameters('notDataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cassandra role definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cassandra role definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the cassandra role definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_cassandraKeyspaces", + "databaseAccount_cassandraRoleDefinitions" + ] + }, + "databaseAccount_mongodbDatabases": { + "copy": { + "name": "databaseAccount_mongodbDatabases", + "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "collections": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "autoscaleSettings": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "13897098552792121791" + }, + "name": "DocumentDB Database Account MongoDB Databases", + "description": "This module deploys a MongoDB Database within a CosmosDB Account." + }, + "definitions": { + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a collection." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "mongodbDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "mongodbDatabase_collections": { + "copy": { + "name": "mongodbDatabase_collections", + "count": "[length(coalesce(parameters('collections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "mongodbDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + }, + "indexes": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + }, + "shardKey": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "16151461445994734468" + }, + "name": "DocumentDB Database Account MongoDB Database Collections", + "description": "This module deploys a MongoDB Database Collection." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "mongodbDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]", + "indexes": "[parameters('indexes')]", + "shardKey": "[parameters('shardKey')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database collection." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database collection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "mongodbDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_gremlinDatabases": { + "copy": { + "name": "databaseAccount_gremlinDatabases", + "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "graphs": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11959636451300474346" + }, + "name": "DocumentDB Database Account Gremlin Databases", + "description": "This module deploys a Gremlin Database within a CosmosDB Account." + }, + "definitions": { + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a graph." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + } + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "gremlinDatabase_gremlinGraphs": { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(coalesce(parameters('graphs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "partitionKeyPaths": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10487122333182352122" + }, + "name": "DocumentDB Database Accounts Gremlin Databases Graphs", + "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount::gremlinDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinGraph": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": "[parameters('indexingPolicy')]", + "partitionKey": { + "paths": "[parameters('partitionKeyPaths')]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "gremlinDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_tables": { + "copy": { + "name": "databaseAccount_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1787500858429182824" + }, + "name": "Azure Cosmos DB account tables", + "description": "This module deploys a table within an Azure Cosmos DB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "table": { + "type": "Microsoft.DocumentDB/databaseAccounts/tables", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraKeyspaces": { + "copy": { + "name": "databaseAccount_cassandraKeyspaces", + "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" + }, + "views": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15257396763463366586" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces", + "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." + }, + "definitions": { + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra table." + } + }, + "viewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra view (materialized view)." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/viewType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraKeyspace": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "cassandraKeyspace_tables": { + "copy": { + "name": "cassandraKeyspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "schema": { + "value": "[parameters('tables')[copyIndex()].schema]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + }, + "throughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "defaultTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15998065591386988132" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Tables", + "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra table resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the Cassandra table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "defaultTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraTable": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "schema": "[parameters('schema')]", + "defaultTtl": "[parameters('defaultTtl')]", + "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + }, + "cassandraKeyspace_views": { + "copy": { + "name": "cassandraKeyspace_views", + "count": "[length(parameters('views'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('views')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "viewDefinition": { + "value": "[parameters('views')[copyIndex()].viewDefinition]" + }, + "throughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6617803098467821091" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Views", + "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra view." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags of the Cassandra view resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraView": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "viewDefinition": "[parameters('viewDefinition')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra view." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra view." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra view was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra keyspace." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra keyspace." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra keyspace was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_privateEndpoints": { + "copy": { + "name": "databaseAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the database account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the database account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the database account was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the database account." + }, + "value": "[reference('databaseAccount').documentEndpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "primaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" + }, + "primaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" + }, + "primaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" + }, + "primaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" + }, + "secondaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" + }, + "secondaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" + }, + "secondaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" + }, + "secondaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" + } + } + } + }, + "dependsOn": [ + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", + "virtualNetwork" + ] + }, + "avmAiSearch": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('srch-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "basic" + }, + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8530209533589901450" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Diagnostic settings for monitoring." + } + }, + "privateEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Private endpoint configurations." + } + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of role assignments to create on the AI Search service." + } + } + }, + "resources": { + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" + } + }, + "searchServiceUpdate": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.search.update.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "sku": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": "[equals(parameters('managedIdentityType'), 'SystemAssigned')]" + } + }, + "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "6207719545398489494" + }, + "name": "Search Services", + "description": "This module deploys a Search Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the API Admin keys generated by the modules." + } + }, + "primaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAdminKey secret name to create." + } + }, + "secondaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAdminKey secret name to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." + } + }, + "authOptions": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/authOptions" + }, + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + }, + "nullable": true + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "computeType": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Confidential", + "Default" + ], + "metadata": { + "description": "Optional. The compute type of the search service." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "dataExfiltrationProtections": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Optional. A list of data exfiltration scenarios that are explicitly disallowed for the search service. Currently, the only supported value is 'All' to disable all possible data export scenarios with more fine grained controls planned for the future." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings for all Resources in the solution." + } + }, + "networkRuleSet": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/networkRuleSet" + }, + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + }, + "nullable": true + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to help categorize the resource in the Azure portal." + }, + "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', '')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "authOptions": "[parameters('authOptions')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]", + "computeType": "[parameters('computeType')]", + "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" + } + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "2115224445601868607" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource." + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "696453183181258843" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2025-05-01', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[reference('searchService').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryKey": { + "type": "securestring", + "metadata": { + "description": "The primary admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" + }, + "secondaryKey": { + "type": "securestring", + "metadata": { + "description": "The secondaryKey admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." + }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" + } + } + } + } + }, + "avmAppConfig": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('location')]" + } + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "sku": { + "value": "Standard" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "disableLocalAuth": { + "value": false + }, + "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + } + ] + }, + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_PROCESS", + "value": "Processes" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMA", + "value": "Schemas" + }, + { + "name": "APP_COSMOS_DATABASE", + "value": "ContentProcess" + }, + { + "name": "APP_CPS_CONFIGURATION", + "value": "cps-configuration" + }, + { + "name": "APP_CPS_MAX_FILESIZE_MB", + "value": "20" + }, + { + "name": "APP_CPS_PROCESSES", + "value": "cps-processes" + }, + { + "name": "APP_MESSAGE_QUEUE_EXTRACT", + "value": "content-pipeline-extract-queue" + }, + { + "name": "APP_MESSAGE_QUEUE_INTERVAL", + "value": "5" + }, + { + "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", + "value": "180" + }, + { + "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", + "value": "10" + }, + { + "name": "APP_PROCESS_STEPS", + "value": "extract,map,evaluate,save" + }, + { + "name": "APP_STORAGE_BLOB_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" + }, + { + "name": "APP_STORAGE_QUEUE_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" + }, + { + "name": "APP_COSMOS_CONNSTR", + "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", + "value": "claimprocesses" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCHES", + "value": "batches" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMASET", + "value": "Schemasets" + }, + { + "name": "APP_CPS_PROCESS_BATCH", + "value": "process-batch" + }, + { + "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", + "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" + }, + { + "name": "APP_CPS_POLL_INTERVAL_SECONDS", + "value": "3" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference('avmStorageAccount').outputs.name.value]" + }, + { + "name": "CLAIM_PROCESS_QUEUE_NAME", + "value": "claim-process-queue" + }, + { + "name": "DEAD_LETTER_QUEUE_NAME", + "value": "claim-process-dead-letter-queue" + }, + { + "name": "AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", + "value": "[parameters('gptModelName')]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_OPENAI_ENDPOINT_BASE", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", + "value": "" + }, + { + "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", + "value": "" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + }, + { + "name": "GLOBAL_LLM_SERVICE", + "value": "AzureOpenAI" + }, + { + "name": "GPT5_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "GPT5_CHAT_DEPLOYMENT_NAME", + "value": "gpt-5" + }, + { + "name": "GPT5_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "PHI4_API_VERSION", + "value": "2024-05-01-preview" + }, + { + "name": "PHI4_CHAT_DEPLOYMENT_NAME", + "value": "phi-4" + }, + { + "name": "PHI4_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + } + ] + }, + "publicNetworkAccess": { + "value": "Enabled" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the app configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the app configuration." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration store was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the app configuration." + }, + "value": "[reference('configurationStore').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the app configuration." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } + } + } + }, + "dependsOn": [ + "avmAiServices", + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Web", + "avmContainerApp_Workflow", + "avmCosmosDB", + "avmStorageAccount", + "logAnalyticsWorkspace" + ] + }, + "avmAppConfig_update": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "privateEndpoints": { + "value": [ + { + "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", + "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "name": "appconfig-dns-zone-group", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" + } + ] + }, + "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the app configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the app configuration." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration store was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the app configuration." + }, + "value": "[reference('configurationStore').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the app configuration." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } + } + } + }, + "dependsOn": [ + "avmAppConfig", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", + "virtualNetwork" + ] + }, + "avmContainerApp_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" + ] + }, + "avmContainerApp_API_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" + ] + }, + "avmContainerApp_Workflow_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + } + }, + "outputs": { + "CONTAINER_WEB_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for Web App." + }, + "value": "[reference('avmContainerApp_Web').outputs.name.value]" + }, + "CONTAINER_API_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for API." + }, + "value": "[reference('avmContainerApp_API').outputs.name.value]" + }, + "CONTAINER_WEB_APP_FQDN": { + "type": "string", + "metadata": { + "description": "The FQDN of the Container App." + }, + "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" + }, + "CONTAINER_API_APP_FQDN": { + "type": "string", + "metadata": { + "description": "The FQDN of the Container App API." + }, + "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" + }, + "CONTAINER_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for APP." + }, + "value": "[reference('avmContainerApp').outputs.name.value]" + }, + "CONTAINER_WORKFLOW_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for Workflow." + }, + "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" + }, + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "metadata": { + "description": "The user identity resource ID used fot the Container APP." + }, + "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", + "metadata": { + "description": "The user identity Principal ID used fot the Container APP." + }, + "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "metadata": { + "description": "The login server of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "metadata": { + "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." + }, + "value": "[reference('avmAiServices').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "metadata": { + "description": "The resource group the resources were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "SOLUTION_NAME": { + "type": "string", + "metadata": { + "description": "The solution name." + }, + "value": "[parameters('solutionName')]" + } + } +} \ No newline at end of file diff --git a/infra/bicep/main.bicep b/infra/bicep/main.bicep new file mode 100644 index 00000000..3a3b9f19 --- /dev/null +++ b/infra/bicep/main.bicep @@ -0,0 +1,794 @@ +targetScope = 'resourceGroup' + +metadata name = 'Content Processing Solution Accelerator - Bicep' +metadata description = 'Deploys Content Processing resources using the restored private-repo module interfaces.' + +@minLength(3) +@maxLength(20) +param solutionName string = 'cps' + +@metadata({ azd: { type: 'location' } }) +param location string + +@metadata({ azd: { type: 'location' } }) +param azureAiServiceLocation string + +param gptModelName string = 'gpt-5.1' +param containerRegistryEndpoint string = '' +param imageTag string = 'latest_v2' +param enablePrivateNetworking bool = false +param enableMonitoring bool = false +param enableRedundancy bool = false +param enableScalability bool = false +param enableTelemetry bool = true +param enablePurgeProtection bool = false +param tags object = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location +} + +var uniqueToken = substring(uniqueString(subscription().subscriptionId, resourceGroup().id, solutionName), 0, 5) +var solutionSuffix = toLower(replace(replace(replace('${solutionName}${uniqueToken}', '-', ''), '_', ''), '.', '')) + +var managedIdentityName = 'id-${solutionSuffix}' +var containerRegistryName = replace('cr${solutionSuffix}', '-', '') +var storageAccountName = take(replace('st${solutionSuffix}', '-', ''), 24) +var cosmosDbName = 'cosmos-${solutionSuffix}' +var cosmosDatabaseName = 'contentprocessing' +var cosmosContainerName = 'documents' +var aiServicesName = 'aif-${solutionSuffix}' +var aiProjectName = 'proj-${solutionSuffix}' +var aiSearchName = 'srch-${solutionSuffix}' +var appConfigurationName = 'appcs-${solutionSuffix}' +var containerAppEnvironmentName = 'cae-${solutionSuffix}' +var contentProcessorAppName = 'ca-${solutionSuffix}-app' +var contentProcessorApiName = 'ca-${solutionSuffix}-api' +var contentProcessorWebName = 'ca-${solutionSuffix}-web' +var contentProcessorWorkflowName = 'ca-${solutionSuffix}-wkfl' +var modelDeploymentName = 'gpt-${solutionSuffix}' +var storageContainerName = 'content' +var storageQueueName = 'content' + +var acrPullRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') +var storageBlobDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') +var storageQueueDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88') +var appConfigurationDataReaderRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071') +var cognitiveServicesOpenAiUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd') +var cognitiveServicesUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908') +var azureAiDeveloperRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee') + +module logAnalytics './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { + name: take('module.log-analytics.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + location: location + tags: tags + } +} + +module appInsights './modules/monitoring/app-insights.bicep' = if (enableMonitoring) { + name: take('module.app-insights.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + location: location + workspaceResourceId: logAnalytics!.outputs.resourceId + tags: tags + } +} + +module managedIdentity './modules/identity/managed-identity.bicep' = { + name: take('module.managed-identity.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + identityName: managedIdentityName + location: location + tags: tags + } +} + +module containerRegistry './modules/compute/container-registry.bicep' = { + name: take('module.container-registry.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: containerRegistryName + location: location + sku: enableRedundancy ? 'Premium' : 'Standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + tags: tags + } +} + +module storageAccount './modules/data/storage-account.bicep' = { + name: take('module.storage-account.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: storageAccountName + location: location + skuName: enableRedundancy ? 'Standard_ZRS' : 'Standard_LRS' + containers: [ + { + name: storageContainerName + publicAccess: 'None' + } + ] + tags: tags + } +} + +resource storageAccountResource 'Microsoft.Storage/storageAccounts@2025-08-01' existing = { + name: storageAccountName +} + +resource queueService 'Microsoft.Storage/storageAccounts/queueServices@2025-08-01' = { + parent: storageAccountResource + name: 'default' +} + +resource storageQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@2025-08-01' = { + parent: queueService + name: storageQueueName +} + +resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { + name: cosmosDbName + location: location + kind: 'MongoDB' + tags: tags + properties: { + databaseAccountOfferType: 'Standard' + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: enableRedundancy + } + ] + capabilities: [ + { + name: 'EnableMongo' + } + ] + apiProperties: { + serverVersion: '7.0' + } + disableLocalAuth: false + enableAutomaticFailover: false + enableMultipleWriteLocations: false + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + } +} + +resource cosmosMongoDatabase 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2023-04-15' = { + parent: cosmosDb + name: cosmosDatabaseName + properties: { + resource: { + id: cosmosDatabaseName + } + options: {} + } +} + +resource cosmosMongoCollection 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2023-04-15' = { + parent: cosmosMongoDatabase + name: cosmosContainerName + properties: { + resource: { + id: cosmosContainerName + shardKey: { + id: 'Hash' + } + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + ] + } + options: {} + } +} + +module aiFoundry './modules/ai/ai-foundry.bicep' = { + name: take('module.ai-foundry.${solutionSuffix}', 64) + params: { + name: aiServicesName + location: azureAiServiceLocation + principalIds: [] + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + tags: union(tags, { + location: azureAiServiceLocation + }) + } +} + +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesName +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { + parent: aiServicesAccount + name: aiProjectName + location: azureAiServiceLocation + kind: 'AIServices' + identity: { + type: 'SystemAssigned' + } + tags: union(tags, { + location: azureAiServiceLocation + }) + properties: {} +} + +module modelDeployment './modules/ai/ai-foundry-model-deployment.bicep' = { + name: take('module.ai-model.${solutionSuffix}', 64) + params: { + aiServicesAccountName: aiFoundry.outputs.name + deploymentName: modelDeploymentName + modelName: gptModelName + skuName: 'GlobalStandard' + skuCapacity: 10 + } +} + +module aiSearch './modules/ai/ai-search.bicep' = { + name: take('module.ai-search.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: aiSearchName + location: location + replicaCount: enableRedundancy ? 2 : 1 + partitionCount: enableScalability ? 2 : 1 + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + tags: tags + } +} + +module containerAppEnvironment './modules/compute/container-app-environment.bicep' = { + name: take('module.container-app-environment.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: containerAppEnvironmentName + location: location + logAnalyticsWorkspaceResourceId: enableMonitoring ? logAnalytics!.outputs.resourceId : '' + zoneRedundant: enableRedundancy + tags: tags + } +} + +var effectiveContainerRegistryEndpoint = empty(containerRegistryEndpoint) ? containerRegistry.outputs.loginServer : containerRegistryEndpoint +var apiAppFqdn = '${contentProcessorApiName}.${containerAppEnvironment.outputs.defaultDomain}' +var webAppFqdn = '${contentProcessorWebName}.${containerAppEnvironment.outputs.defaultDomain}' +var workflowAppFqdn = '${contentProcessorWorkflowName}.${containerAppEnvironment.outputs.defaultDomain}' +var cosmosDbEndpoint = 'https://${cosmosDb.name}.mongo.cosmos.azure.com:443/' + +var sharedEnv = [ + { + name: 'APP_CONFIG_ENDPOINT' + value: appConfiguration.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? appInsights!.outputs.connectionString : '' + } +] + +var apiProbes = [ + { + type: 'Liveness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 + periodSeconds: 5 + failureThreshold: 10 + } +] + +var appConfigurationValues = [ + { + name: 'APP_AZURE_OPENAI_ENDPOINT' + value: aiFoundry.outputs.endpoint + } + { + name: 'APP_AZURE_OPENAI_MODEL' + value: gptModelName + } + { + name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' + value: aiFoundry.outputs.endpoint + } + { + name: 'APP_AI_PROJECT_ENDPOINT' + value: aiProject.properties.endpoints['AI Foundry API'] + } + { + name: 'APP_COSMOS_DB_ENDPOINT' + value: cosmosDbEndpoint + } + { + name: 'APP_COSMOS_DB_NAME' + value: cosmosDatabaseName + } + { + name: 'APP_COSMOS_DB_CONTAINER' + value: cosmosContainerName + } + { + name: 'APP_STORAGE_ACCOUNT_NAME' + value: storageAccount.outputs.name + } + { + name: 'APP_STORAGE_BLOB_ENDPOINT' + value: storageAccount.outputs.blobEndpoint + } + { + name: 'APP_STORAGE_QUEUE_ENDPOINT' + value: storageAccount.outputs.serviceEndpoints.queue + } + { + name: 'APP_STORAGE_CONTAINER_NAME' + value: storageContainerName + } + { + name: 'APP_AI_SEARCH_ENDPOINT' + value: aiSearch.outputs.endpoint + } + { + name: 'APP_AI_SEARCH_INDEX' + value: 'content-index' + } + { + name: 'APP_WORKFLOW_APP_ENDPOINT' + value: 'https://${workflowAppFqdn}' + } + { + name: 'APP_API_ENDPOINT' + value: 'https://${apiAppFqdn}' + } + { + name: 'AZURE_OPENAI_API_VERSION' + value: '2025-03-01-preview' + } + { + name: 'AZURE_TRACING_ENABLED' + value: 'True' + } +] + +module appConfiguration './modules/data/app-configuration.bicep' = { + name: take('module.app-config.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: appConfigurationName + location: location + keyValues: appConfigurationValues + tags: tags + } +} + +module contentProcessorApp './modules/compute/container-app.bicep' = { + name: take('module.content-app.${solutionSuffix}', 64) + params: { + name: contentProcessorAppName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + disableIngress: true + containers: [ + { + name: contentProcessorAppName + image: '${effectiveContainerRegistryEndpoint}/contentprocessor:${imageTag}' + resources: { + cpu: 4 + memory: '8Gi' + } + env: concat(sharedEnv, [ + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' + } + ]) + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + scaleSettings: { + minReplicas: enableScalability ? 2 : 1 + maxReplicas: enableScalability ? 3 : 2 + } + tags: tags + } +} + +module contentProcessorApi './modules/compute/container-app.bicep' = { + name: take('module.content-api.${solutionSuffix}', 64) + params: { + name: contentProcessorApiName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + ingressExternal: true + ingressTargetPort: 80 + containers: [ + { + name: contentProcessorApiName + image: '${effectiveContainerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 2 + memory: '4Gi' + } + env: concat(sharedEnv, [ + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ]) + probes: apiProbes + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + scaleSettings: { + minReplicas: 0 + maxReplicas: 10 + } + tags: tags + } +} + +module contentProcessorWeb './modules/compute/container-app.bicep' = { + name: take('module.content-web.${solutionSuffix}', 64) + params: { + name: contentProcessorWebName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + ingressExternal: true + ingressTargetPort: 80 + containers: [ + { + name: contentProcessorWebName + image: '${effectiveContainerRegistryEndpoint}/contentprocessorweb:${imageTag}' + resources: { + cpu: 2 + memory: '4Gi' + } + env: concat(sharedEnv, [ + { + name: 'APP_API_BASE_URL' + value: 'https://${apiAppFqdn}' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWeb' + } + ]) + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + corsPolicy: { + allowedOrigins: [ + 'https://${apiAppFqdn}' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + '*' + ] + } + scaleSettings: { + minReplicas: 0 + maxReplicas: 10 + } + tags: tags + } +} + +module contentProcessorWorkflow './modules/compute/container-app.bicep' = { + name: take('module.content-workflow.${solutionSuffix}', 64) + params: { + name: contentProcessorWorkflowName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + ingressExternal: true + ingressTargetPort: 80 + containers: [ + { + name: contentProcessorWorkflowName + image: '${effectiveContainerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 2 + memory: '4Gi' + } + env: concat(sharedEnv, [ + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ]) + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + scaleSettings: { + minReplicas: 0 + maxReplicas: 10 + } + tags: tags + } +} + +resource containerRegistryResource 'Microsoft.ContainerRegistry/registries@2025-04-01' existing = { + name: containerRegistryName +} + +resource appConfigurationResource 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = { + name: appConfigurationName +} + +resource acrPullAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerRegistryName, managedIdentityName, 'acr-pull') + scope: containerRegistryResource + properties: { + principalId: managedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: acrPullRoleId + } +} + +resource contentProcessorBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorAppName, 'blob') + scope: storageAccountResource + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageBlobDataContributorRoleId + } +} + +resource contentProcessorApiBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorApiName, 'blob') + scope: storageAccountResource + properties: { + principalId: contentProcessorApi.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageBlobDataContributorRoleId + } +} + +resource contentProcessorWorkflowBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorWorkflowName, 'blob') + scope: storageAccountResource + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageBlobDataContributorRoleId + } +} + +resource contentProcessorQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorAppName, 'queue') + scope: storageAccountResource + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageQueueDataContributorRoleId + } +} + +resource contentProcessorApiQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorApiName, 'queue') + scope: storageAccountResource + properties: { + principalId: contentProcessorApi.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageQueueDataContributorRoleId + } +} + +resource contentProcessorWorkflowQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorWorkflowName, 'queue') + scope: storageAccountResource + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageQueueDataContributorRoleId + } +} + +resource contentProcessorAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorAppName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorApiAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorApiName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorApi.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorWebAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorWebName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorWeb.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorWorkflowAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorWorkflowName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorOpenAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorAppName, 'openai-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesOpenAiUserRoleId + } +} + +resource contentProcessorWorkflowOpenAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorWorkflowName, 'openai-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesOpenAiUserRoleId + } +} + +resource contentProcessorAiDeveloperAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorAppName, 'ai-developer') + scope: aiServicesAccount + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: azureAiDeveloperRoleId + } +} + +resource contentProcessorWorkflowAiDeveloperAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorWorkflowName, 'ai-developer') + scope: aiServicesAccount + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: azureAiDeveloperRoleId + } +} + +resource contentProcessorAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorAppName, 'cog-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesUserRoleId + } +} + +resource contentProcessorWorkflowAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorWorkflowName, 'cog-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesUserRoleId + } +} + +output SOLUTION_NAME string = solutionName +output CONTAINER_WEB_APP_NAME string = contentProcessorWeb.outputs.name +output CONTAINER_API_APP_NAME string = contentProcessorApi.outputs.name +output CONTAINER_WEB_APP_FQDN string = webAppFqdn +output CONTAINER_API_APP_FQDN string = apiAppFqdn +output CONTAINER_APP_NAME string = contentProcessorApp.outputs.name +output CONTAINER_WORKFLOW_APP_NAME string = contentProcessorWorkflow.outputs.name +output CONTAINER_APP_USER_IDENTITY_ID string = managedIdentity.outputs.resourceId +output CONTAINER_APP_USER_PRINCIPAL_ID string = managedIdentity.outputs.principalId +output CONTAINER_REGISTRY_NAME string = containerRegistry.outputs.name +output CONTAINER_REGISTRY_LOGIN_SERVER string = containerRegistry.outputs.loginServer +output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = aiFoundry.outputs.name +output AZURE_RESOURCE_GROUP string = resourceGroup().name diff --git a/infra/bicep/main.json b/infra/bicep/main.json new file mode 100644 index 00000000..53cee80f --- /dev/null +++ b/infra/bicep/main.json @@ -0,0 +1,3406 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6422306545253132015" + }, + "name": "Content Processing Solution Accelerator - Bicep", + "description": "Deploys Content Processing resources using the restored private-repo module interfaces." + }, + "parameters": { + "solutionName": { + "type": "string", + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20 + }, + "location": { + "type": "string", + "metadata": { + "azd": { + "type": "location" + } + } + }, + "azureAiServiceLocation": { + "type": "string", + "metadata": { + "azd": { + "type": "location" + } + } + }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1" + }, + "containerRegistryEndpoint": { + "type": "string", + "defaultValue": "" + }, + "imageTag": { + "type": "string", + "defaultValue": "latest_v2" + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false + }, + "enableScalability": { + "type": "bool", + "defaultValue": false + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false + }, + "tags": { + "type": "object", + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + } + } + }, + "variables": { + "uniqueToken": "[substring(uniqueString(subscription().subscriptionId, resourceGroup().id, parameters('solutionName')), 0, 5)]", + "solutionSuffix": "[toLower(replace(replace(replace(format('{0}{1}', parameters('solutionName'), variables('uniqueToken')), '-', ''), '_', ''), '.', ''))]", + "managedIdentityName": "[format('id-{0}', variables('solutionSuffix'))]", + "containerRegistryName": "[replace(format('cr{0}', variables('solutionSuffix')), '-', '')]", + "storageAccountName": "[take(replace(format('st{0}', variables('solutionSuffix')), '-', ''), 24)]", + "cosmosDbName": "[format('cosmos-{0}', variables('solutionSuffix'))]", + "cosmosDatabaseName": "contentprocessing", + "cosmosContainerName": "documents", + "aiServicesName": "[format('aif-{0}', variables('solutionSuffix'))]", + "aiProjectName": "[format('proj-{0}', variables('solutionSuffix'))]", + "aiSearchName": "[format('srch-{0}', variables('solutionSuffix'))]", + "appConfigurationName": "[format('appcs-{0}', variables('solutionSuffix'))]", + "containerAppEnvironmentName": "[format('cae-{0}', variables('solutionSuffix'))]", + "contentProcessorAppName": "[format('ca-{0}-app', variables('solutionSuffix'))]", + "contentProcessorApiName": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "contentProcessorWebName": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "contentProcessorWorkflowName": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "modelDeploymentName": "[format('gpt-{0}', variables('solutionSuffix'))]", + "storageContainerName": "content", + "storageQueueName": "content", + "acrPullRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "storageBlobDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "storageQueueDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "appConfigurationDataReaderRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "cognitiveServicesOpenAiUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "cognitiveServicesUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "azureAiDeveloperRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "cosmosDbEndpoint": "[format('https://{0}.mongo.cosmos.azure.com:443/', variables('cosmosDbName'))]", + "apiProbes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]" + }, + { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', variables('storageQueueName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageAccountName'), 'default')]" + ] + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2023-04-15", + "name": "[variables('cosmosDbName')]", + "location": "[parameters('location')]", + "kind": "MongoDB", + "tags": "[parameters('tags')]", + "properties": { + "databaseAccountOfferType": "Standard", + "locations": [ + { + "locationName": "[parameters('location')]", + "failoverPriority": 0, + "isZoneRedundant": "[parameters('enableRedundancy')]" + } + ], + "capabilities": [ + { + "name": "EnableMongo" + } + ], + "apiProperties": { + "serverVersion": "7.0" + }, + "disableLocalAuth": false, + "enableAutomaticFailover": false, + "enableMultipleWriteLocations": false, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]" + } + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}', variables('cosmosDbName'), variables('cosmosDatabaseName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosDatabaseName')]" + }, + "options": {} + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]" + ] + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}/{2}', variables('cosmosDbName'), variables('cosmosDatabaseName'), variables('cosmosContainerName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosContainerName')]", + "shardKey": { + "id": "Hash" + }, + "indexes": [ + { + "key": { + "keys": [ + "_id" + ] + } + } + ] + }, + "options": {} + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', variables('cosmosDbName'), variables('cosmosDatabaseName'))]" + ] + }, + { + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', variables('aiServicesName'), variables('aiProjectName'))]", + "location": "[parameters('azureAiServiceLocation')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "tags": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]", + "properties": {} + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', variables('containerRegistryName'))]", + "name": "[guid(variables('containerRegistryName'), variables('managedIdentityName'), 'acr-pull')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('acrPullRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorAppName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorApiName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWebName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWorkflowName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7692694992043508018" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "metadata": { + "description": "SKU name for the workspace." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "retentionInDays": "[parameters('retentionInDays')]", + "sku": { + "name": "[parameters('skuName')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01', 'full').location]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01').customerId]" + } + } + } + } + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "workspaceResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4667471246975862151" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('appi-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace to link to." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Application type." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable IP masking for security." + } + }, + "flowType": { + "type": "string", + "defaultValue": "Bluefield", + "metadata": { + "description": "Flow type for Application Insights." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "web", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "Flow_Type": "[parameters('flowType')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "publicNetworkAccessForIngestion": "Enabled", + "publicNetworkAccessForQuery": "Enabled" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Application Insights instance." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Application Insights instance." + }, + "value": "[parameters('name')]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Instrumentation key for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Connection string for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').ConnectionString]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "Application ID of the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').AppId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[variables('managedIdentityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "14165903959794426055" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the managed identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID (object ID) of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').clientId]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[parameters('identityName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('containerRegistryName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(parameters('enableRedundancy'), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17432455227529690473" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "adminUserEnabled": "[parameters('adminUserEnabled')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "dataEndpointEnabled": false, + "networkRuleBypassOptions": "AzureServices", + "policies": { + "exportPolicy": { + "status": "[parameters('exportPolicyStatus')]" + }, + "retentionPolicy": { + "status": "enabled", + "days": 7 + }, + "trustPolicy": { + "status": "disabled", + "type": "Notary" + } + }, + "zoneRedundancy": "Disabled" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": "[if(parameters('enableRedundancy'), createObject('value', 'Standard_ZRS'), createObject('value', 'Standard_LRS'))]", + "containers": { + "value": [ + { + "name": "[variables('storageContainerName')]", + "publicAccess": "None" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17696053432794478605" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[take(format('st{0}', toLower(replace(parameters('solutionName'), '-', ''))), 24)]", + "metadata": { + "description": "Name of the storage account." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_LRS", + "metadata": { + "description": "Storage account SKU." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "metadata": { + "description": "Storage account kind." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Hot", + "Cool" + ], + "metadata": { + "description": "Access tier." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Allow blob public access." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Allow shared key access." + } + }, + "containers": { + "type": "array", + "defaultValue": [ + { + "name": "default", + "publicAccess": "None" + } + ], + "metadata": { + "description": "Blob containers to create." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "properties": { + "accessTier": "[parameters('accessTier')]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "minimumTlsVersion": "TLS1_2", + "supportsHttpsTrafficOnly": true, + "encryption": { + "services": { + "blob": { + "enabled": true + }, + "file": { + "enabled": true + } + }, + "keySource": "Microsoft.Storage", + "requireInfrastructureEncryption": true + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "blobContainers", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', parameters('containers')[copyIndex()].name)]", + "properties": { + "publicAccess": "[parameters('containers')[copyIndex()].publicAccess]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('name'), 'default')]" + ] + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Storage Account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Storage Account." + }, + "value": "[parameters('name')]" + }, + "blobEndpoint": { + "type": "string", + "metadata": { + "description": "Primary blob endpoint." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.blob]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('aiServicesName')]" + }, + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "principalIds": { + "value": [] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7594344478012985364" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services account." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Required. Azure region for the resource." + } + }, + "principalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether public network access is allowed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to apply to the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "sku": { + "name": "S0" + }, + "properties": { + "customSubDomainName": "[parameters('name')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "disableLocalAuth": true, + "allowProjectManagement": true, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" + } + } + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principalIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", + "properties": { + "principalId": "[parameters('principalIds')[copyIndex()]]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AI Services account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the AI Services account." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the AI Services account." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01').endpoint]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01', 'full').identity.principalId]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-model.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "aiServicesAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "deploymentName": { + "value": "[variables('modelDeploymentName')]" + }, + "modelName": { + "value": "[parameters('gptModelName')]" + }, + "skuName": { + "value": "GlobalStandard" + }, + "skuCapacity": { + "value": 10 + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18411757618261752815" + } + }, + "parameters": { + "aiServicesAccountName": { + "type": "string", + "metadata": { + "description": "Required. Name of the parent AI Services account." + } + }, + "deploymentName": { + "type": "string", + "metadata": { + "description": "Required. Name for this model deployment." + } + }, + "modelFormat": { + "type": "string", + "defaultValue": "OpenAI", + "metadata": { + "description": "Optional. Model format (e.g., OpenAI)." + } + }, + "modelName": { + "type": "string", + "metadata": { + "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." + } + }, + "modelVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Model version. Empty string means latest." + } + }, + "raiPolicyName": { + "type": "string", + "defaultValue": "Microsoft.Default", + "metadata": { + "description": "Optional. RAI policy name." + } + }, + "skuName": { + "type": "string", + "metadata": { + "description": "Required. SKU name (e.g., Standard, GlobalStandard)." + } + }, + "skuCapacity": { + "type": "int", + "metadata": { + "description": "Required. SKU capacity (tokens per minute in thousands)." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", + "properties": { + "model": { + "format": "[parameters('modelFormat')]", + "name": "[parameters('modelName')]", + "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" + }, + "raiPolicyName": "[parameters('raiPolicyName')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacity": "[parameters('skuCapacity')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the deployed model." + }, + "value": "[parameters('deploymentName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the model deployment." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('aiSearchName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "714050788324647491" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "searchServiceUpdate", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "managedIdentityType": { + "value": "[parameters('managedIdentityType')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3683977219901178221" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the existing AI Search service." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The Azure region of the search service." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": { + "type": "[parameters('managedIdentityType')]" + }, + "properties": { + "replicaCount": "[parameters('replicaCount')]", + "partitionCount": "[parameters('partitionCount')]", + "hostingMode": "[parameters('hostingMode')]", + "semanticSearch": "[parameters('semanticSearch')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + } + } + ], + "outputs": { + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the AI Search system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.Search/searchServices', parameters('name')), '2025-05-01', 'full').identity.principalId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + ] + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." + }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'searchServiceUpdate'), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('containerAppEnvironmentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17265155980354931238" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the Container Apps Environment." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + } + }, + "infrastructureSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for VNet integration (optional)." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable zone redundancy." + } + } + }, + "resources": [ + { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "appLogsConfiguration": { + "destination": "log-analytics", + "logAnalyticsConfiguration": { + "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", + "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" + } + }, + "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", + "zoneRedundant": "[parameters('zoneRedundant')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container Apps Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container Apps Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The default domain of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The static IP address of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-config.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('appConfigurationName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName')), '2025-12-01').endpoints['AI Foundry API']]" + }, + { + "name": "APP_COSMOS_DB_ENDPOINT", + "value": "[variables('cosmosDbEndpoint')]" + }, + { + "name": "APP_COSMOS_DB_NAME", + "value": "[variables('cosmosDatabaseName')]" + }, + { + "name": "APP_COSMOS_DB_CONTAINER", + "value": "[variables('cosmosContainerName')]" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "APP_STORAGE_BLOB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.blobEndpoint.value]" + }, + { + "name": "APP_STORAGE_QUEUE_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_STORAGE_CONTAINER_NAME", + "value": "[variables('storageContainerName')]" + }, + { + "name": "APP_AI_SEARCH_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_SEARCH_INDEX", + "value": "content-index" + }, + { + "name": "APP_WORKFLOW_APP_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "APP_API_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18286182317157861590" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the App Configuration store." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Standard" + ], + "metadata": { + "description": "SKU for the configuration store." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Disable local (key-based) authentication." + } + }, + "keyValues": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Key-value pairs to store in the configuration." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2023-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "Enabled" + } + }, + { + "copy": { + "name": "configurationKeyValues", + "count": "[length(parameters('keyValues'))]" + }, + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", + "properties": { + "value": "[parameters('keyValues')[copyIndex()].value]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the App Configuration store." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the App Configuration store." + }, + "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the App Configuration store." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-app.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "disableIngress": { + "value": true + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorAppName')]", + "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]" + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-api.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorApiName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorApiName')]", + "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", + "probes": "[variables('apiProbes')]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-web.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorWebName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWebName')]", + "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "*" + ] + } + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorWorkflowName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWorkflowName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + } + ], + "outputs": { + "SOLUTION_NAME": { + "type": "string", + "value": "[parameters('solutionName')]" + }, + "CONTAINER_WEB_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_API_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_WEB_APP_FQDN": { + "type": "string", + "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + }, + "CONTAINER_API_APP_FQDN": { + "type": "string", + "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + }, + "CONTAINER_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_WORKFLOW_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/infra/main.bicep b/infra/main.bicep index 9f4ec91e..5e816126 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -1,1860 +1,209 @@ -// ========== main.bicep ========== // +// ============================================================================ +// main.bicep — Deployment Router +// Description: Routes deployment to the appropriate infrastructure flavor. +// - 'bicep' → Vanilla Bicep modules (Docker deployment) +// - 'avm' → AVM-based modules (non-WAF) +// - 'avm-waf' → AVM-based modules with WAF-aligned features +// (monitoring, private networking, scalability, redundancy) +// ============================================================================ targetScope = 'resourceGroup' -metadata name = 'Content Processing Solution Accelerator' -metadata description = 'Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance.' +// ============================================================================ +// Routing Parameter +// ============================================================================ + +@allowed([ + 'bicep' + 'avm' + 'avm-waf' +]) +@description('Required. Deployment flavor: bicep (vanilla Docker), avm (AVM non-WAF), or avm-waf (AVM WAF-aligned).') +param deploymentFlavor string = 'avm' + +// ============================================================================ +// Parameters — Core +// ============================================================================ -// ========== Parameters ========== // @minLength(3) @maxLength(20) -@description('Optional. Name of the solution to deploy. This should be 3-20 characters long.') +@description('Optional. Name of the solution to deploy.') param solutionName string = 'cps' @metadata({ azd: { type: 'location' } }) -@description('Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).') -@allowed([ - 'australiaeast' - 'centralus' - 'eastasia' - 'eastus2' - 'japaneast' - 'northeurope' - 'southeastasia' - 'uksouth' -]) +@description('Required. Azure region for the deployment.') param location string -@minLength(1) -@allowed([ - 'australiaeast' - 'eastus' - 'eastus2' - 'japaneast' - 'southcentralus' - 'southeastasia' - 'swedencentral' - 'uksouth' - 'westeurope' - 'westus' - 'westus3' -]) -@description('Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead.') -@metadata({ - azd: { - type: 'location' - usageName: [ - 'OpenAI.GlobalStandard.gpt-5.1,300' - ] - } -}) +@metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for Azure AI services resources.') param azureAiServiceLocation string -@description('Optional. Type of GPT deployment to use: Standard | GlobalStandard.') -@minLength(1) +// ============================================================================ +// Parameters — AI Configuration +// ============================================================================ + +@description('Optional. Name of the GPT model deployment.') +param gptModelName string = 'gpt-5.1' + @allowed([ 'Standard' 'GlobalStandard' ]) +@description('Optional. Type of GPT deployment: Standard | GlobalStandard.') param deploymentType string = 'GlobalStandard' -@description('Optional. Name of the GPT model to deploy: gpt-5.1') -param gptModelName string = 'gpt-5.1' - -@minLength(1) -@description('Optional. Version of the GPT model to deploy:.') -@allowed([ - '2025-11-13' -]) +@description('Optional. Version of the GPT model.') param gptModelVersion string = '2025-11-13' -@minValue(1) -@description('Optional. Capacity of the GPT deployment: (minimum 10).') +@description('Optional. Capacity (TPM) for the GPT deployment.') param gptDeploymentCapacity int = 300 -@description('Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint).') -param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' +// ============================================================================ +// Parameters — Existing Resources +// ============================================================================ + +@description('Optional. Resource ID of an existing Log Analytics workspace. Leave empty to create a new one.') +param existingLogAnalyticsWorkspaceId string = '' + +@description('Optional. Resource ID of an existing AI Foundry project. Leave empty to create a new one.') +param existingFoundryProjectResourceId string = '' + +// ============================================================================ +// Parameters — Compute +// ============================================================================ + +@description('Optional. Container registry endpoint. Leave empty to use the deployed ACR login server.') +param containerRegistryEndpoint string = '' -@description('Optional. The image tag for the container images.') +@description('Optional. Image tag for all container images.') param imageTag string = 'latest_v2' -@description('Optional. Enable WAF for the deployment.') -param enablePrivateNetworking bool = false +// ============================================================================ +// Parameters — Feature Flags +// ============================================================================ -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true +@description('Optional. Enable private networking.') +param enablePrivateNetworking bool = false -@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') +@description('Optional. Enable monitoring resources.') param enableMonitoring bool = false -@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +@description('Optional. Enable redundancy for supported resources.') param enableRedundancy bool = false -@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +@description('Optional. Enable higher scale defaults for supported resources.') param enableScalability bool = false -@description('Optional. Enable purge protection. Defaults to false.') -param enablePurgeProtection bool = false - -@description('Optional. Tags to be applied to the resources.') -param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} - -@description('Optional: Existing Log Analytics Workspace Resource ID') -param existingLogAnalyticsWorkspaceId string = '' +@description('Optional. Enable AVM telemetry.') +param enableTelemetry bool = true -@description('Use this parameter to use an existing AI project resource ID') -param existingFoundryProjectResourceId string = '' +@description('Optional. Enable purge protection for App Configuration.') +param enablePurgeProtection bool = false -@description('Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true.') -param vmSize string = '' +// ============================================================================ +// Parameters — WAF (AVM-WAF only) +// ============================================================================ -@description('Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') -@secure() +@description('Optional. VM admin username for WAF jumpbox (avm-waf only).') param vmAdminUsername string = '' -@description('Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') @secure() +@description('Optional. VM admin password for WAF jumpbox (avm-waf only).') param vmAdminPassword string = '' -@maxLength(5) -@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') -param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) - -var solutionSuffix = toLower(trim(replace( - replace( - replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), - ' ', - '' - ), - '*', - '' -))) -// ============== // -// Resources // -// ============== // - -var existingProjectResourceId = trim(existingFoundryProjectResourceId) - -// ========== AVM Telemetry ========== // -#disable-next-line no-deployments-resources -resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { - name: take( - '46d3xbcp.ptn.sa-contentprocessing.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', - 64 - ) - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } - } - } - } -} - -// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. -var replicaRegionPairs = { - australiaeast: 'australiasoutheast' - centralus: 'westus' - eastasia: 'japaneast' - eastus: 'centralus' - eastus2: 'centralus' - japaneast: 'eastasia' - northeurope: 'westeurope' - southeastasia: 'eastasia' - uksouth: 'westeurope' - westeurope: 'northeurope' -} -var replicaLocation = replicaRegionPairs[?location] - -// ========== Virtual Network ========== // -module virtualNetwork './modules/virtualNetwork.bicep' = if (enablePrivateNetworking) { - name: take('module.virtual-network.${solutionSuffix}', 64) - params: { - name: 'vnet-${solutionSuffix}' - addressPrefixes: ['10.0.0.0/8'] - location: location - tags: tags - logAnalyticsWorkspaceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - resourceSuffix: solutionSuffix - enableTelemetry: enableTelemetry - } -} - -// Azure Bastion Host -var bastionHostName = 'bas-${solutionSuffix}' -module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePrivateNetworking) { - name: take('avm.res.network.bastion-host.${bastionHostName}', 64) - params: { - name: bastionHostName - skuName: 'Standard' - location: location - virtualNetworkResourceId: virtualNetwork!.outputs.resourceId - diagnosticSettings: enableMonitoring - ? [ - { - name: 'bastionDiagnostics' - workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] - } - ] - : null - tags: tags - enableTelemetry: enableTelemetry - publicIPAddressObject: { - name: 'pip-${bastionHostName}' - } - } -} - -// ========== VM Maintenance Configuration Mapping ========== // +@description('Optional. VM size for WAF jumpbox (avm-waf only).') +param vmSize string = '' -// Jumpbox Virtual Machine -var jumpboxVmName = take('vm-${solutionSuffix}', 15) -module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enablePrivateNetworking) { - name: take('avm.res.compute.virtual-machine.${jumpboxVmName}', 64) - params: { - name: jumpboxVmName - location: location - tags: tags - enableTelemetry: enableTelemetry - computerName: take(jumpboxVmName, 15) - osType: 'Windows' - vmSize: empty(vmSize) ? 'Standard_D2s_v5' : vmSize - adminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername - adminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword - managedIdentities: { - systemAssigned: true - } - patchMode: 'AutomaticByPlatform' - bypassPlatformSafetyChecksOnUserSchedule: true - maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId - enableAutomaticUpdates: true - encryptionAtHost: false - availabilityZone: enableRedundancy ? 1 : -1 - imageReference: { - publisher: 'microsoft-dsvm' - offer: 'dsvm-win-2022' - sku: 'winserver-2022' - version: 'latest' - } - osDisk: { - name: 'osdisk-${jumpboxVmName}' - caching: 'ReadWrite' - createOption: 'FromImage' - deleteOption: 'Delete' - diskSizeGB: 128 - managedDisk: { - // WAF aligned configuration - use Premium storage for better SLA when redundancy is enabled - storageAccountType: enableRedundancy ? 'Premium_LRS' : 'Standard_LRS' - } - } - nicConfigurations: [ - { - name: 'nic-${jumpboxVmName}' - tags: tags - deleteOption: 'Delete' - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring - ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] - : null - ipConfigurations: [ - { - name: '${jumpboxVmName}-nic01-ipconfig01' - subnetResourceId: virtualNetwork!.outputs.adminSubnetResourceId - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring - ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] - : null - } - ] - } - ] - extensionAadJoinConfig: { - enabled: true - tags: tags - typeHandlerVersion: '1.0' - settings: { - mdmId:'' - } - } - extensionAntiMalwareConfig: { - enabled: true - settings: { - AntimalwareEnabled: 'true' - Exclusions: {} - RealtimeProtectionEnabled: 'true' - ScheduledScanSettings: { - day: '7' - isEnabled: 'true' - scanType: 'Quick' - time: '120' - } - } - tags: tags - } - //WAF aligned configuration for Monitoring - extensionMonitoringAgentConfig: enableMonitoring - ? { - dataCollectionRuleAssociations: [ - { - dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId - name: 'send-${logAnalyticsWorkspace!.outputs.name}' - } - ] - enabled: true - tags: tags - } - : null - extensionNetworkWatcherAgentConfig: { - enabled: true - tags: tags - } - } -} +// ============================================================================ +// Parameters — Tags +// ============================================================================ -module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = if (enablePrivateNetworking) { - name: take('avm.res.maintenance-configuration.${jumpboxVmName}', 64) - params: { - name: 'mc-${jumpboxVmName}' - location: location - tags: tags - enableTelemetry: enableTelemetry - extensionProperties: { - InGuestPatchMode: 'User' - } - maintenanceScope: 'InGuestPatch' - maintenanceWindow: { - startDateTime: '2024-06-16 00:00' - duration: '03:55' - timeZone: 'W. Europe Standard Time' - recurEvery: '1Day' - } - visibility: 'Custom' - installPatches: { - rebootSetting: 'IfRequired' - windowsParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } - linuxParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } - } - } +@description('Optional. Tags to be applied to resources.') +param tags object = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location } -var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' -var dataCollectionRulesLocation = logAnalyticsWorkspace!.outputs.location -var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' -var dcrLogAnalyticsDestinationName = 'la-${logAnalyticsWorkspaceResourceName}-destination' -module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.11.0' = if (enablePrivateNetworking && enableMonitoring) { - name: take('avm.res.insights.data-collection-rule.${dataCollectionRulesResourceName}', 64) - params: { - name: dataCollectionRulesResourceName - tags: tags - enableTelemetry: enableTelemetry - location: dataCollectionRulesLocation - dataCollectionRuleProperties: { - kind: 'Windows' - dataSources: { - performanceCounters: [ - { - streams: [ - 'Microsoft-Perf' - ] - samplingFrequencyInSeconds: 60 - counterSpecifiers: [ - '\\Processor Information(_Total)\\% Processor Time' - '\\Processor Information(_Total)\\% Privileged Time' - '\\Processor Information(_Total)\\% User Time' - '\\Processor Information(_Total)\\Processor Frequency' - '\\System\\Processes' - '\\Process(_Total)\\Thread Count' - '\\Process(_Total)\\Handle Count' - '\\System\\System Up Time' - '\\System\\Context Switches/sec' - '\\System\\Processor Queue Length' - '\\Memory\\% Committed Bytes In Use' - '\\Memory\\Available Bytes' - '\\Memory\\Committed Bytes' - '\\Memory\\Cache Bytes' - '\\Memory\\Pool Paged Bytes' - '\\Memory\\Pool Nonpaged Bytes' - '\\Memory\\Pages/sec' - '\\Memory\\Page Faults/sec' - '\\Process(_Total)\\Working Set' - '\\Process(_Total)\\Working Set - Private' - '\\LogicalDisk(_Total)\\% Disk Time' - '\\LogicalDisk(_Total)\\% Disk Read Time' - '\\LogicalDisk(_Total)\\% Disk Write Time' - '\\LogicalDisk(_Total)\\% Idle Time' - '\\LogicalDisk(_Total)\\Disk Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Transfers/sec' - '\\LogicalDisk(_Total)\\Disk Reads/sec' - '\\LogicalDisk(_Total)\\Disk Writes/sec' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' - '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' - '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' - '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' - '\\LogicalDisk(_Total)\\% Free Space' - '\\LogicalDisk(_Total)\\Free Megabytes' - '\\Network Interface(*)\\Bytes Total/sec' - '\\Network Interface(*)\\Bytes Sent/sec' - '\\Network Interface(*)\\Bytes Received/sec' - '\\Network Interface(*)\\Packets/sec' - '\\Network Interface(*)\\Packets Sent/sec' - '\\Network Interface(*)\\Packets Received/sec' - '\\Network Interface(*)\\Packets Outbound Errors' - '\\Network Interface(*)\\Packets Received Errors' - ] - name: 'perfCounterDataSource60' - } - ] - windowsEventLogs: [ - { - name: 'SecurityAuditEvents' - streams: [ - 'Microsoft-Event' - ] - xPathQueries: [ - 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' - ] - } - ] - } - destinations: { - logAnalytics: [ - { - workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId - name: dcrLogAnalyticsDestinationName - } - ] - } - dataFlows: [ - { - streams: [ - 'Microsoft-Perf' - ] - destinations: [ - dcrLogAnalyticsDestinationName - ] - transformKql: 'source' - outputStream: 'Microsoft-Perf' - } - { - streams: [ - 'Microsoft-Event' - ] - destinations: [ - dcrLogAnalyticsDestinationName - ] - transformKql: 'source' - outputStream: 'Microsoft-Event' - } - ] - } - } -} +// ============================================================================ +// Derived Variables +// ============================================================================ -// ========== Private DNS Zones ========== // -var privateDnsZones = [ - 'privatelink.cognitiveservices.azure.com' - 'privatelink.openai.azure.com' - 'privatelink.services.ai.azure.com' - 'privatelink.contentunderstanding.ai.azure.com' - 'privatelink.blob.${environment().suffixes.storage}' - 'privatelink.queue.${environment().suffixes.storage}' - 'privatelink.mongo.cosmos.azure.com' - 'privatelink.azconfig.io' - 'privatelink.azurecr.io' -] +var isAvm = deploymentFlavor == 'avm' || deploymentFlavor == 'avm-waf' +var isBicep = deploymentFlavor == 'bicep' +var useWafDefaults = deploymentFlavor == 'avm-waf' -// DNS Zone Index Constants -var dnsZoneIndex = { - cognitiveServices: 0 - openAI: 1 - aiServices: 2 - contentUnderstanding: 3 - storageBlob: 4 - storageQueue: 5 - cosmosDB: 6 - appConfig: 7 - containerRegistry: 8 -} +var effectiveEnablePrivateNetworking = useWafDefaults ? true : enablePrivateNetworking +var effectiveEnableMonitoring = useWafDefaults ? true : enableMonitoring +var effectiveEnableRedundancy = useWafDefaults ? true : enableRedundancy +var effectiveEnableScalability = useWafDefaults ? true : enableScalability -@batchSize(5) -module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ - for (zone, i) in privateDnsZones: if (enablePrivateNetworking) { - name: take('avm.res.network.private-dns-zone.${split(zone, '.')[1]}', 64) - params: { - name: zone - tags: tags - enableTelemetry: enableTelemetry - virtualNetworkLinks: [{ virtualNetworkResourceId: virtualNetwork!.outputs.resourceId }] - } - } -] +// ============================================================================ +// Module: AVM Deployment +// ============================================================================ -// ========== Log Analytics & Application Insights ========== // -module logAnalyticsWorkspace 'modules/log-analytics-workspace.bicep' = if (enableMonitoring) { - name: take('module.log-analytics-workspace.${solutionSuffix}', 64) +module avmDeployment './avm/main.bicep' = if (isAvm) { + name: take('module.avm.${solutionName}', 64) params: { - name: logAnalyticsWorkspaceResourceName + solutionName: solutionName location: location - tags: tags - enableTelemetry: enableTelemetry + azureAiServiceLocation: azureAiServiceLocation + gptModelName: gptModelName + deploymentType: deploymentType + gptModelVersion: gptModelVersion + gptDeploymentCapacity: gptDeploymentCapacity existingLogAnalyticsWorkspaceId: existingLogAnalyticsWorkspaceId - enablePrivateNetworking: enablePrivateNetworking - enableRedundancy: enableRedundancy - replicaLocation: replicaLocation - } -} - -module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (enableMonitoring) { - name: take('avm.res.insights.component.${solutionSuffix}', 64) - params: { - name: 'appi-${solutionSuffix}' - location: location - enableTelemetry: enableTelemetry - retentionInDays: 365 - kind: 'web' - disableIpMasking: false - flowType: 'Bluefield' - // WAF aligned configuration for Monitoring - workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null - tags: tags - } -} - -@description('Optional. Tag, Created by user name.') -param createdBy string = contains(deployer(), 'userPrincipalName') - ? split(deployer().userPrincipalName, '@')[0] - : deployer().objectId - -// ========== Resource Group Tag ========== // -resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { - name: 'default' - properties: { - tags: { - ...resourceGroup().tags - ...tags - TemplateName: 'Content Processing' - Type: enablePrivateNetworking ? 'WAF' : 'Non-WAF' - CreatedBy: createdBy - DeploymentName: deployment().name - } - } -} - -// ========== Managed Identity ========== // -module avmManagedIdentity './modules/managed-identity.bicep' = { - name: take('module.managed-identity.${solutionSuffix}', 64) - params: { - name: 'id-${solutionSuffix}' - location: location - tags: tags - enableTelemetry: enableTelemetry - } -} - -module avmContainerRegistry 'modules/container-registry.bicep' = { - name: take('module.container-registry.${solutionSuffix}', 64) - params: { - acrName: 'cr${replace(solutionSuffix, '-', '')}' - location: location - acrSku: enableRedundancy || enablePrivateNetworking ? 'Premium' : 'Standard' - publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' - zoneRedundancy: 'Disabled' - roleAssignments: [ - { - principalId: avmContainerRegistryReader.outputs.principalId - roleDefinitionIdOrName: 'AcrPull' - principalType: 'ServicePrincipal' - } - ] - tags: tags + existingFoundryProjectResourceId: existingFoundryProjectResourceId + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enablePrivateNetworking: effectiveEnablePrivateNetworking + enableMonitoring: effectiveEnableMonitoring + enableRedundancy: effectiveEnableRedundancy + enableScalability: effectiveEnableScalability enableTelemetry: enableTelemetry - enableRedundancy: enableRedundancy - replicaLocation: replicaLocation - enablePrivateNetworking: enablePrivateNetworking - backendSubnetResourceId: enablePrivateNetworking ? virtualNetwork!.outputs.backendSubnetResourceId : '' - privateDnsZoneResourceId: enablePrivateNetworking - ? avmPrivateDnsZones[dnsZoneIndex.containerRegistry]!.outputs.resourceId - : '' - } -} - -// // ========== Storage Account ========== // -module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { - name: take('module.storage-account.${solutionSuffix}', 64) - params: { - name: 'st${replace(solutionSuffix, '-', '')}' - location: location - managedIdentities: { systemAssigned: true } - minimumTlsVersion: 'TLS1_2' - enableTelemetry: enableTelemetry - roleAssignments: [ - { - principalId: avmManagedIdentity.outputs.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - ] - networkAcls: { - bypass: 'AzureServices' - defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' - ipRules: [] - } - requireInfrastructureEncryption: true - supportsHttpsTrafficOnly: true - accessTier: 'Hot' - tags: tags - - //<======================= WAF related parameters - allowBlobPublicAccess: false - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - privateEndpoints: (enablePrivateNetworking) - ? [ - { - name: 'pep-blob-${solutionSuffix}' - customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'storage-dns-zone-group-blob' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - service: 'blob' - } - { - name: 'pep-queue-${solutionSuffix}' - customNetworkInterfaceName: 'nic-queue-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'storage-dns-zone-group-queue' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageQueue]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - service: 'queue' - } - ] - : [] - } -} - -// // ========== AI Foundry and related resources ========== // -module avmAiServices 'modules/account/aifoundry.bicep' = { - name: take('module.ai-services.${solutionSuffix}', 64) - params: { - name: 'aif-${solutionSuffix}' - projectName: 'proj-${solutionSuffix}' - projectDescription: 'proj-${solutionSuffix}' - existingFoundryProjectResourceId: existingProjectResourceId - location: azureAiServiceLocation - sku: 'S0' - allowProjectManagement: true - managedIdentities: { systemAssigned: true } - kind: 'AIServices' - tags: { - app: solutionSuffix - location: azureAiServiceLocation - } - customSubDomainName: 'aif-${solutionSuffix}' - diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null - roleAssignments: [ - { - principalId: avmManagedIdentity.outputs.principalId - roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Azure AI Developer' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Azure AI Developer' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services User' - principalType: 'ServicePrincipal' - } - ] - networkAcls: { - bypass: 'AzureServices' - defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' - } - disableLocalAuth: true - enableTelemetry: enableTelemetry - deployments: [ - { - name: gptModelName - model: { - format: 'OpenAI' - name: gptModelName - version: gptModelVersion - } - sku: { - name: deploymentType - capacity: gptDeploymentCapacity - } - raiPolicyName: 'Microsoft.Default' - } - ] - - // WAF related parameters - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - //publicNetworkAccess: 'Enabled' // Always enabled for AI Services - } -} - -module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking && empty(existingProjectResourceId)) { - name: take('avm.res.network.private-endpoint.${solutionSuffix}', 64) - params: { - name: 'pep-aiservices-${solutionSuffix}' - location: location - tags: tags - customNetworkInterfaceName: 'nic-aiservices-${solutionSuffix}' - privateLinkServiceConnections: [ - { - name: 'pep-aiservices-${solutionSuffix}-cognitiveservices-connection' - properties: { - privateLinkServiceId: avmAiServices.outputs.resourceId - groupIds: ['account'] - } - } - ] - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'ai-services-dns-zone-cognitiveservices' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId - } - { - name: 'ai-services-dns-zone-openai' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId - } - { - name: 'ai-services-dns-zone-aiservices' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId - } - { - name: 'ai-services-dns-zone-contentunderstanding' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId - } -} - -// ========== Container App Environment ========== // -module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { - name: take('avm.res.app.managed-environment.${solutionSuffix}', 64) - params: { - name: 'cae-${solutionSuffix}' - location: location - tags: { - ...resourceGroup().tags - ...tags - } - managedIdentities: { systemAssigned: true } - appLogsConfiguration: enableMonitoring - ? { - destination: 'log-analytics' - logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId - } - : null - workloadProfiles: [ - { - name: 'Consumption' - workloadProfileType: 'Consumption' - } - ] - enableTelemetry: enableTelemetry - publicNetworkAccess: 'Enabled' // Always enabled for Container Apps Environment - - // <========== WAF related parameters - - platformReservedCidr: '172.17.17.0/24' - platformReservedDnsIP: '172.17.17.17' - zoneRedundant: (enablePrivateNetworking) ? true : false // Enable zone redundancy if private networking is enabled - infrastructureSubnetResourceId: (enablePrivateNetworking) - ? virtualNetwork!.outputs.containersSubnetResourceId // Use the container app subnet - : null // Use the container app subnet - } -} - -// //=========== Managed Identity for Container Registry ========== // -module avmContainerRegistryReader 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { - name: take('avm.res.managed-identity.user-assigned-identity.${solutionSuffix}', 64) - params: { - name: 'id-acr-${solutionSuffix}' - location: location - tags: tags - enableTelemetry: enableTelemetry - } -} - -// ========== Container App ========== // -module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-app' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - - containers: [ - { - name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessor' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } - tags: tags - } -} - -// ========== Container App API ========== // -module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-api.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-api' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorAPI' - } - ] - probes: [ - // Liveness Probe - Checks if the app is still running - { - type: 'Liveness' - httpGet: { - path: '/startup' // Your app must expose this endpoint - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - // Readiness Probe - Checks if the app is ready to receive traffic - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 // Wait 10s before checking - periodSeconds: 5 // Check every 15s - failureThreshold: 10 // Restart if it fails 5 times - } - ] - } - ] - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - ingressExternal: true - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - corsPolicy: { - allowedOrigins: [ - '*' - ] - allowedMethods: [ - 'GET' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - ] - allowedHeaders: [ - 'Authorization' - 'Content-Type' - '*' - ] - } - } -} - -//========== Container App Web ========== // -module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-web.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-web' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - ingressExternal: true - ingressTargetPort: 3000 - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-web' - image: '${containerRegistryEndpoint}/contentprocessorweb:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_API_BASE_URL' - value: 'https://${avmContainerApp_API.outputs.fqdn}' - } - { - name: 'APP_WEB_CLIENT_ID' - value: '' - } - { - name: 'APP_WEB_AUTHORITY' - value: '${environment().authentication.loginEndpoint}/${tenant().tenantId}' - } - { - name: 'APP_WEB_SCOPE' - value: '' - } - { - name: 'APP_API_SCOPE' - value: '' - } - { - name: 'APP_REDIRECT_URL' - value: '/' - } - { - name: 'APP_POST_REDIRECT_URL' - value: '/' - } - { - name: 'APP_CONSOLE_LOG_ENABLED' - value: 'false' - } - ] - } - ] - } -} - -// ========== Container App Workflow ========== // -module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-wkfl.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-wkfl' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorWorkflow' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } - } -} - -// ========== Cosmos Database for Mongo DB ========== // -module avmCosmosDB 'br/public:avm/res/document-db/database-account:0.19.0' = { - name: take('avm.res.document-db.database-account.${solutionSuffix}', 64) - params: { - name: 'cosmos-${solutionSuffix}' - location: location - mongodbDatabases: [ - { - name: 'default' - tag: 'default database' - } - ] - tags: tags - enableTelemetry: enableTelemetry - databaseAccountOfferType: 'Standard' - enableAutomaticFailover: false - serverVersion: '7.0' - capabilitiesToAdd: [ - 'EnableMongo' - ] - defaultConsistencyLevel: 'Session' - maxIntervalInSeconds: 5 - maxStalenessPrefix: 100 - zoneRedundant: false - - // WAF related parameters - networkRestrictions: { - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - ipRules: [] - virtualNetworkRules: [] - } - - privateEndpoints: (enablePrivateNetworking) - ? [ - { - name: 'pep-cosmosdb-${solutionSuffix}' - customNetworkInterfaceName: 'nic-cosmosdb-${solutionSuffix}' - privateEndpointResourceId: virtualNetwork!.outputs.resourceId - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'cosmosdb-dns-zone-group' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId - } - ] - } - service: 'MongoDB' - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - } - ] - : [] - } -} - -// ========== App Configuration ========== // -module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { - name: take('avm.res.app.configuration-store.${solutionSuffix}', 64) - params: { - name: 'appcs-${solutionSuffix}' - location: location - enablePurgeProtection: enablePurgeProtection - tags: { - app: solutionSuffix - location: location - } - enableTelemetry: enableTelemetry - managedIdentities: { systemAssigned: true } - sku: 'Standard' - diagnosticSettings: enableMonitoring - ? [ - { - workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] - } - ] - : null - disableLocalAuth: false - replicaLocations: enableRedundancy? [{ replicaLocation: replicaLocation }] : [] - roleAssignments: [ - { - principalId: avmContainerApp.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_API.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Web.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - ] - keyValues: [ - { - name: 'APP_AZURE_OPENAI_ENDPOINT' - value: avmAiServices.outputs.endpoint //TODO: replace with actual endpoint - } - { - name: 'APP_AZURE_OPENAI_MODEL' - value: gptModelName - } - { - name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - { - name: 'APP_COSMOS_CONTAINER_PROCESS' - value: 'Processes' - } - { - name: 'APP_COSMOS_CONTAINER_SCHEMA' - value: 'Schemas' - } - { - name: 'APP_COSMOS_DATABASE' - value: 'ContentProcess' - } - { - name: 'APP_CPS_CONFIGURATION' - value: 'cps-configuration' - } - { - name: 'APP_CPS_MAX_FILESIZE_MB' - value: '20' - } - { - name: 'APP_CPS_PROCESSES' - value: 'cps-processes' - } - { - name: 'APP_MESSAGE_QUEUE_EXTRACT' - value: 'content-pipeline-extract-queue' - } - { - name: 'APP_MESSAGE_QUEUE_INTERVAL' - value: '5' - } - { - name: 'APP_MESSAGE_QUEUE_PROCESS_TIMEOUT' - value: '180' - } - { - name: 'APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT' - value: '10' - } - { - name: 'APP_PROCESS_STEPS' - value: 'extract,map,evaluate,save' - } - { - name: 'APP_STORAGE_BLOB_URL' - value: avmStorageAccount.outputs.serviceEndpoints.blob - } - { - name: 'APP_STORAGE_QUEUE_URL' - value: avmStorageAccount.outputs.serviceEndpoints.queue - } - { - name: 'APP_AI_PROJECT_ENDPOINT' - value: avmAiServices.outputs.aiProjectInfo.?apiEndpoint ?? '' - } - { - name: 'APP_COSMOS_CONNSTR' - value: avmCosmosDB.outputs.primaryReadWriteConnectionString - } - // ===== v2 Workflow Keys ===== // - { - name: 'APP_COSMOS_CONTAINER_BATCH_PROCESS' - value: 'claimprocesses' - } - { - name: 'APP_COSMOS_CONTAINER_BATCHES' - value: 'batches' - } - { - name: 'APP_COSMOS_CONTAINER_SCHEMASET' - value: 'Schemasets' - } - { - name: 'APP_CPS_PROCESS_BATCH' - value: 'process-batch' - } - { - name: 'APP_CPS_CONTENT_PROCESS_ENDPOINT' - value: 'http://${avmContainerApp_API.outputs.name}/' - } - { - name: 'APP_CPS_POLL_INTERVAL_SECONDS' - value: '3' - } - { - name: 'APP_STORAGE_ACCOUNT_NAME' - value: avmStorageAccount.outputs.name - } - { - name: 'CLAIM_PROCESS_QUEUE_NAME' - value: 'claim-process-queue' - } - { - name: 'DEAD_LETTER_QUEUE_NAME' - value: 'claim-process-dead-letter-queue' - } - { - name: 'AZURE_OPENAI_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - { - name: 'AZURE_OPENAI_CHAT_DEPLOYMENT_NAME' - value: gptModelName - } - { - name: 'AZURE_OPENAI_API_VERSION' - value: '2025-03-01-preview' - } - { - name: 'AZURE_OPENAI_ENDPOINT_BASE' - value: avmAiServices.outputs.endpoint - } - // ===== Agent Framework Keys ===== // - { - name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' - value: '' - } - { - name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' - value: '' - } - { - name: 'AZURE_TRACING_ENABLED' - value: 'True' - } - { - name: 'GLOBAL_LLM_SERVICE' - value: 'AzureOpenAI' - } - // ===== GPT-5 Service Prefix Keys ===== // - { - name: 'GPT5_API_VERSION' - value: '2025-03-01-preview' - } - { - name: 'GPT5_CHAT_DEPLOYMENT_NAME' - value: 'gpt-5' - } - { - name: 'GPT5_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - // ===== PHI-4 Service Prefix Keys ===== // - { - name: 'PHI4_API_VERSION' - value: '2024-05-01-preview' - } - { - name: 'PHI4_CHAT_DEPLOYMENT_NAME' - value: 'phi-4' - } - { - name: 'PHI4_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - ] - - publicNetworkAccess: 'Enabled' - } -} - -module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = if (enablePrivateNetworking) { - name: take('avm.res.app.configuration-store.update.${solutionSuffix}', 64) - params: { - name: 'appcs-${solutionSuffix}' - location: location enablePurgeProtection: enablePurgeProtection - enableTelemetry: enableTelemetry + vmAdminUsername: vmAdminUsername + vmAdminPassword: vmAdminPassword + vmSize: vmSize tags: tags - publicNetworkAccess: 'Disabled' - privateEndpoints: [ - { - name: 'pep-appconfig-${solutionSuffix}' - customNetworkInterfaceName: 'nic-appconfig-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'appconfig-dns-zone-group' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.appConfig]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - } - ] } - - dependsOn: [ - avmAppConfig - ] } -// ========== Container App Update Modules ========== // -module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-update.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-app' - location: location - enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessor' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: enableScalability - ? [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: 100 - } - } - } - ] - : [] - } - } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] -} +// ============================================================================ +// Module: Vanilla Bicep Deployment +// ============================================================================ -module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) +module bicepDeployment './bicep/main.bicep' = if (isBicep) { + name: take('module.bicep.${solutionName}', 64) params: { - name: 'ca-${solutionSuffix}-api' + solutionName: solutionName location: location + azureAiServiceLocation: azureAiServiceLocation + gptModelName: gptModelName + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enablePrivateNetworking: effectiveEnablePrivateNetworking + enableMonitoring: effectiveEnableMonitoring + enableRedundancy: effectiveEnableRedundancy + enableScalability: effectiveEnableScalability enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - - containers: [ - { - name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorAPI' - } - ] - probes: [ - // Liveness Probe - Checks if the app is still running - { - type: 'Liveness' - httpGet: { - path: '/startup' // Your app must expose this endpoint - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - // Readiness Probe - Checks if the app is ready to receive traffic - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 // Wait 10s before checking - periodSeconds: 5 // Check every 15s - failureThreshold: 10 // Restart if it fails 5 times - } - ] - } - ] - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - ingressExternal: true - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - corsPolicy: { - allowedOrigins: [ - '*' - ] - allowedMethods: [ - 'GET' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - ] - allowedHeaders: [ - 'Authorization' - 'Content-Type' - '*' - ] - } - } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] -} - -// ========== Container App Workflow Update ========== // -module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-wkfl' - location: location - enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null + enablePurgeProtection: enablePurgeProtection tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorWorkflow' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } } } -// ============ // -// Outputs // -// ============ // - -@description('The name of the Container App used for Web App.') -output CONTAINER_WEB_APP_NAME string = avmContainerApp_Web.outputs.name - -@description('The name of the Container App used for API.') -output CONTAINER_API_APP_NAME string = avmContainerApp_API.outputs.name - -@description('The FQDN of the Container App.') -output CONTAINER_WEB_APP_FQDN string = avmContainerApp_Web.outputs.fqdn - -@description('The FQDN of the Container App API.') -output CONTAINER_API_APP_FQDN string = avmContainerApp_API.outputs.fqdn - -@description('The name of the Container App used for APP.') -output CONTAINER_APP_NAME string = avmContainerApp.outputs.name - -@description('The name of the Container App used for Workflow.') -output CONTAINER_WORKFLOW_APP_NAME string = avmContainerApp_Workflow.outputs.name - -@description('The user identity resource ID used fot the Container APP.') -output CONTAINER_APP_USER_IDENTITY_ID string = avmContainerRegistryReader.outputs.resourceId - -@description('The user identity Principal ID used fot the Container APP.') -output CONTAINER_APP_USER_PRINCIPAL_ID string = avmContainerRegistryReader.outputs.principalId - -@description('The name of the Azure Container Registry.') -output CONTAINER_REGISTRY_NAME string = avmContainerRegistry.outputs.name - -@description('The login server of the Azure Container Registry.') -output CONTAINER_REGISTRY_LOGIN_SERVER string = avmContainerRegistry.outputs.loginServer - -@description('The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA.') -output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices.outputs.name +// ============================================================================ +// Outputs — Coalesced from whichever flavor was deployed +// ============================================================================ -@description('The resource group the resources were deployed into.') -output AZURE_RESOURCE_GROUP string = resourceGroup().name +output SOLUTION_NAME string = isAvm ? avmDeployment!.outputs.SOLUTION_NAME : bicepDeployment!.outputs.SOLUTION_NAME +output CONTAINER_WEB_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_WEB_APP_NAME : bicepDeployment!.outputs.CONTAINER_WEB_APP_NAME +output CONTAINER_API_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_API_APP_NAME : bicepDeployment!.outputs.CONTAINER_API_APP_NAME +output CONTAINER_WEB_APP_FQDN string = isAvm ? avmDeployment!.outputs.CONTAINER_WEB_APP_FQDN : bicepDeployment!.outputs.CONTAINER_WEB_APP_FQDN +output CONTAINER_API_APP_FQDN string = isAvm ? avmDeployment!.outputs.CONTAINER_API_APP_FQDN : bicepDeployment!.outputs.CONTAINER_API_APP_FQDN +output CONTAINER_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_NAME : bicepDeployment!.outputs.CONTAINER_APP_NAME +output CONTAINER_WORKFLOW_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_WORKFLOW_APP_NAME : bicepDeployment!.outputs.CONTAINER_WORKFLOW_APP_NAME +output CONTAINER_APP_USER_IDENTITY_ID string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_USER_IDENTITY_ID : bicepDeployment!.outputs.CONTAINER_APP_USER_IDENTITY_ID +output CONTAINER_APP_USER_PRINCIPAL_ID string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_USER_PRINCIPAL_ID : bicepDeployment!.outputs.CONTAINER_APP_USER_PRINCIPAL_ID +output CONTAINER_REGISTRY_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_REGISTRY_NAME : bicepDeployment!.outputs.CONTAINER_REGISTRY_NAME +output CONTAINER_REGISTRY_LOGIN_SERVER string = isAvm ? avmDeployment!.outputs.CONTAINER_REGISTRY_LOGIN_SERVER : bicepDeployment!.outputs.CONTAINER_REGISTRY_LOGIN_SERVER +output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = isAvm ? avmDeployment!.outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME : bicepDeployment!.outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME +output AZURE_RESOURCE_GROUP string = isAvm ? avmDeployment!.outputs.AZURE_RESOURCE_GROUP : bicepDeployment!.outputs.AZURE_RESOURCE_GROUP diff --git a/infra/main.json b/infra/main.json index e8ba8e73..fbefa771 100644 --- a/infra/main.json +++ b/infra/main.json @@ -1,70 +1,59 @@ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "5885652317352749587" - }, - "name": "Content Processing Solution Accelerator", - "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." + "templateHash": "15979971030931723082" + } }, "parameters": { + "deploymentFlavor": { + "type": "string", + "defaultValue": "avm", + "allowedValues": [ + "bicep", + "avm", + "avm-waf" + ], + "metadata": { + "description": "Required. Deployment flavor: bicep (vanilla Docker), avm (AVM non-WAF), or avm-waf (AVM WAF-aligned)." + } + }, "solutionName": { "type": "string", "defaultValue": "cps", "minLength": 3, "maxLength": 20, "metadata": { - "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." + "description": "Optional. Name of the solution to deploy." } }, "location": { "type": "string", - "allowedValues": [ - "australiaeast", - "centralus", - "eastasia", - "eastus2", - "japaneast", - "northeurope", - "southeastasia", - "uksouth" - ], "metadata": { "azd": { "type": "location" }, - "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." + "description": "Required. Azure region for the deployment." } }, "azureAiServiceLocation": { "type": "string", - "allowedValues": [ - "australiaeast", - "eastus", - "eastus2", - "japaneast", - "southcentralus", - "southeastasia", - "swedencentral", - "uksouth", - "westeurope", - "westus", - "westus3" - ], "metadata": { "azd": { - "type": "location", - "usageName": [ - "OpenAI.GlobalStandard.gpt-5.1,300" - ] + "type": "location" }, - "description": "Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead." - }, - "minLength": 1 + "description": "Required. Azure region for Azure AI services resources." + } + }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1", + "metadata": { + "description": "Optional. Name of the GPT model deployment." + } }, "deploymentType": { "type": "string", @@ -73,261 +62,209 @@ "Standard", "GlobalStandard" ], - "minLength": 1, - "metadata": { - "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." - } - }, - "gptModelName": { - "type": "string", - "defaultValue": "gpt-5.1", "metadata": { - "description": "Optional. Name of the GPT model to deploy: gpt-5.1" + "description": "Optional. Type of GPT deployment: Standard | GlobalStandard." } }, "gptModelVersion": { "type": "string", "defaultValue": "2025-11-13", - "allowedValues": [ - "2025-11-13" - ], - "minLength": 1, "metadata": { - "description": "Optional. Version of the GPT model to deploy:." + "description": "Optional. Version of the GPT model." } }, "gptDeploymentCapacity": { "type": "int", "defaultValue": 300, - "minValue": 1, "metadata": { - "description": "Optional. Capacity of the GPT deployment: (minimum 10)." + "description": "Optional. Capacity (TPM) for the GPT deployment." + } + }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an existing Log Analytics workspace. Leave empty to create a new one." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an existing AI Foundry project. Leave empty to create a new one." } }, "containerRegistryEndpoint": { "type": "string", - "defaultValue": "cpscontainerreg.azurecr.io", + "defaultValue": "", "metadata": { - "description": "Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint)." + "description": "Optional. Container registry endpoint. Leave empty to use the deployed ACR login server." } }, "imageTag": { "type": "string", "defaultValue": "latest_v2", "metadata": { - "description": "Optional. The image tag for the container images." + "description": "Optional. Image tag for all container images." } }, "enablePrivateNetworking": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable WAF for the deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Enable private networking." } }, "enableMonitoring": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + "description": "Optional. Enable monitoring resources." } }, "enableRedundancy": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + "description": "Optional. Enable redundancy for supported resources." } }, "enableScalability": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + "description": "Optional. Enable higher scale defaults for supported resources." } }, - "enablePurgeProtection": { + "enableTelemetry": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable purge protection. Defaults to false." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" - }, - "description": "Optional. Tags to be applied to the resources." - }, - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - } - }, - "existingLogAnalyticsWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Existing Log Analytics Workspace Resource ID" - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "", + "defaultValue": true, "metadata": { - "description": "Use this parameter to use an existing AI project resource ID" + "description": "Optional. Enable AVM telemetry." } }, - "vmSize": { - "type": "string", - "defaultValue": "", + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + "description": "Optional. Enable purge protection for App Configuration." } }, "vmAdminUsername": { - "type": "securestring", + "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + "description": "Optional. VM admin username for WAF jumpbox (avm-waf only)." } }, "vmAdminPassword": { "type": "securestring", "defaultValue": "", "metadata": { - "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + "description": "Optional. VM admin password for WAF jumpbox (avm-waf only)." } }, - "solutionUniqueText": { + "vmSize": { "type": "string", - "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", - "maxLength": 5, + "defaultValue": "", "metadata": { - "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." + "description": "Optional. VM size for WAF jumpbox (avm-waf only)." } }, - "createdBy": { - "type": "string", - "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", + "tags": { + "type": "object", + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + }, "metadata": { - "description": "Optional. Tag, Created by user name." + "description": "Optional. Tags to be applied to resources." } } }, "variables": { - "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", - "existingProjectResourceId": "[trim(parameters('existingFoundryProjectResourceId'))]", - "replicaRegionPairs": { - "australiaeast": "australiasoutheast", - "centralus": "westus", - "eastasia": "japaneast", - "eastus": "centralus", - "eastus2": "centralus", - "japaneast": "eastasia", - "northeurope": "westeurope", - "southeastasia": "eastasia", - "uksouth": "westeurope", - "westeurope": "northeurope" - }, - "replicaLocation": "[tryGet(variables('replicaRegionPairs'), parameters('location'))]", - "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", - "jumpboxVmName": "[take(format('vm-{0}', variables('solutionSuffix')), 15)]", - "dataCollectionRulesResourceName": "[format('dcr-{0}', variables('solutionSuffix'))]", - "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", - "dcrLogAnalyticsDestinationName": "[format('la-{0}-destination', variables('logAnalyticsWorkspaceResourceName'))]", - "privateDnsZones": [ - "privatelink.cognitiveservices.azure.com", - "privatelink.openai.azure.com", - "privatelink.services.ai.azure.com", - "privatelink.contentunderstanding.ai.azure.com", - "[format('privatelink.blob.{0}', environment().suffixes.storage)]", - "[format('privatelink.queue.{0}', environment().suffixes.storage)]", - "privatelink.mongo.cosmos.azure.com", - "privatelink.azconfig.io", - "privatelink.azurecr.io" - ], - "dnsZoneIndex": { - "cognitiveServices": 0, - "openAI": 1, - "aiServices": 2, - "contentUnderstanding": 3, - "storageBlob": 4, - "storageQueue": 5, - "cosmosDB": 6, - "appConfig": 7, - "containerRegistry": 8 - } + "isAvm": "[or(equals(parameters('deploymentFlavor'), 'avm'), equals(parameters('deploymentFlavor'), 'avm-waf'))]", + "isBicep": "[equals(parameters('deploymentFlavor'), 'bicep')]", + "useWafDefaults": "[equals(parameters('deploymentFlavor'), 'avm-waf')]", + "effectiveEnablePrivateNetworking": "[if(variables('useWafDefaults'), true(), parameters('enablePrivateNetworking'))]", + "effectiveEnableMonitoring": "[if(variables('useWafDefaults'), true(), parameters('enableMonitoring'))]", + "effectiveEnableRedundancy": "[if(variables('useWafDefaults'), true(), parameters('enableRedundancy'))]", + "effectiveEnableScalability": "[if(variables('useWafDefaults'), true(), parameters('enableScalability'))]" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('46d3xbcp.ptn.sa-contentprocessing.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "resourceGroupTags": { - "type": "Microsoft.Resources/tags", - "apiVersion": "2025-04-01", - "name": "default", - "properties": { - "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" - } - }, - "virtualNetwork": { - "condition": "[parameters('enablePrivateNetworking')]", + "resources": [ + { + "condition": "[variables('isAvm')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.avm.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('vnet-{0}', variables('solutionSuffix'))]" - }, - "addressPrefixes": { - "value": [ - "10.0.0.0/8" - ] + "solutionName": { + "value": "[parameters('solutionName')]" }, "location": { "value": "[parameters('location')]" }, - "tags": { - "value": "[parameters('tags')]" + "azureAiServiceLocation": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "gptModelName": { + "value": "[parameters('gptModelName')]" + }, + "deploymentType": { + "value": "[parameters('deploymentType')]" + }, + "gptModelVersion": { + "value": "[parameters('gptModelVersion')]" + }, + "gptDeploymentCapacity": { + "value": "[parameters('gptDeploymentCapacity')]" + }, + "existingLogAnalyticsWorkspaceId": { + "value": "[parameters('existingLogAnalyticsWorkspaceId')]" + }, + "existingFoundryProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enablePrivateNetworking": { + "value": "[variables('effectiveEnablePrivateNetworking')]" }, - "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "resourceSuffix": { - "value": "[variables('solutionSuffix')]" + "enableMonitoring": { + "value": "[variables('effectiveEnableMonitoring')]" + }, + "enableRedundancy": { + "value": "[variables('effectiveEnableRedundancy')]" + }, + "enableScalability": { + "value": "[variables('effectiveEnableScalability')]" }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "vmAdminUsername": { + "value": "[parameters('vmAdminUsername')]" + }, + "vmAdminPassword": { + "value": "[parameters('vmAdminPassword')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -338,469 +275,326 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "10219602196309243204" - } + "templateHash": "12171467271723171429" + }, + "name": "Content Processing Solution Accelerator", + "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." }, - "definitions": { - "subnetOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the subnet." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the subnet." - } - }, - "nsgName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The name of the associated network security group, if any." - } - }, - "nsgResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The resource ID of the associated network security group, if any." - } - } - }, + "parameters": { + "solutionName": { + "type": "string", + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20, "metadata": { - "__bicep_export!": true, - "description": "Custom type definition for subnet resource information as output" + "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." } }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. Prefixes for the subnet." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable apply network policies on private link service in the subnet." - } - }, - "networkSecurityGroup": { - "$ref": "#/definitions/networkSecurityGroupType", - "nullable": true, - "metadata": { - "description": "Optional. Network Security Group configuration for the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of service endpoint policies." - } + "location": { + "type": "string", + "allowedValues": [ + "australiaeast", + "centralus", + "eastasia", + "eastus2", + "japaneast", + "northeurope", + "southeastasia", + "uksouth" + ], + "metadata": { + "azd": { + "type": "location" }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } + "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." + } + }, + "azureAiServiceLocation": { + "type": "string", + "allowedValues": [ + "australiaeast", + "eastus", + "eastus2", + "japaneast", + "southcentralus", + "southeastasia", + "swedencentral", + "uksouth", + "westeurope", + "westus", + "westus3" + ], + "metadata": { + "azd": { + "type": "location", + "usageName": [ + "OpenAI.GlobalStandard.gpt-5.1,300" + ] }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - } + "description": "Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead." }, + "minLength": 1 + }, + "deploymentType": { + "type": "string", + "defaultValue": "GlobalStandard", + "allowedValues": [ + "Standard", + "GlobalStandard" + ], + "minLength": 1, "metadata": { - "__bicep_export!": true, - "description": "Custom type definition for subnet configuration" + "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." } }, - "networkSecurityGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network security group." - } - }, - "securityRules": { - "type": "array", - "items": { - "type": "object" - }, - "metadata": { - "description": "Required. The security rules for the network security group." - } - } - }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1", "metadata": { - "__bicep_export!": true, - "description": "Custom type definition for network security group configuration" + "description": "Optional. Name of the GPT model to deploy: gpt-5.1" } - } - }, - "parameters": { - "name": { + }, + "gptModelVersion": { "type": "string", + "defaultValue": "2025-11-13", + "allowedValues": [ + "2025-11-13" + ], + "minLength": 1, "metadata": { - "description": "Required. Name of the virtual network." + "description": "Optional. Version of the GPT model to deploy:." } }, - "location": { + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": 300, + "minValue": 1, + "metadata": { + "description": "Optional. Capacity of the GPT deployment: (minimum 10)." + } + }, + "containerRegistryEndpoint": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "cpscontainerreg.azurecr.io", "metadata": { - "description": "Optional. Azure region to deploy resources." + "description": "Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint)." } }, - "addressPrefixes": { - "type": "array", + "imageTag": { + "type": "string", + "defaultValue": "latest_v2", "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + "description": "Optional. The image tag for the container images." } }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "defaultValue": [ - { - "name": "containers", - "addressPrefixes": [ - "10.0.2.0/24" - ], - "delegation": "Microsoft.App/environments", - "networkSecurityGroup": { - "name": "nsg-containers", - "securityRules": [ - { - "name": "AllowHttpsInbound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 100, - "protocol": "Tcp", - "sourceAddressPrefix": "Internet", - "sourcePortRange": "*", - "destinationPortRanges": [ - "443", - "80" - ], - "destinationAddressPrefixes": [ - "10.0.2.0/24" - ] - } - }, - { - "name": "AllowAzureLoadBalancerInbound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 102, - "protocol": "*", - "sourceAddressPrefix": "AzureLoadBalancer", - "sourcePortRange": "*", - "destinationPortRanges": [ - "30000-32767" - ], - "destinationAddressPrefixes": [ - "10.0.2.0/24" - ] - } - }, - { - "name": "AllowSideCarsInbound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 103, - "protocol": "*", - "sourcePortRange": "*", - "sourceAddressPrefixes": [ - "10.0.2.0/24" - ], - "destinationPortRange": "*", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowOutboundToAzureServices", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 200, - "protocol": "*", - "sourceAddressPrefixes": [ - "10.0.2.0/24" - ], - "sourcePortRange": "*", - "destinationPortRange": "*", - "destinationAddressPrefix": "*" - } - }, - { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "direction": "Outbound", - "priority": 100, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "3389", - "22" - ], - "sourceAddressPrefix": "VirtualNetwork", - "destinationAddressPrefix": "*" - } - } - ] - } - }, - { - "name": "backend", - "addressPrefixes": [ - "10.0.0.0/24" - ], - "privateEndpointNetworkPolicies": "Disabled", - "privateLinkServiceNetworkPolicies": "Disabled", - "networkSecurityGroup": { - "name": "nsg-backend", - "securityRules": [ - { - "name": "Deny-hop-outbound", - "properties": { - "access": "Deny", - "direction": "Outbound", - "priority": 200, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "3389", - "22" - ], - "sourceAddressPrefix": "VirtualNetwork", - "destinationAddressPrefix": "*" - } - } - ] - } - }, - { - "name": "AzureBastionSubnet", - "addressPrefixes": [ - "10.0.1.32/27" - ], - "networkSecurityGroup": { - "name": "nsg-bastion", - "securityRules": [ - { - "name": "AllowGatewayManager", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2702, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "GatewayManager", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowHttpsInBound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2703, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "Internet", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowSshRdpOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 100, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AllowAzureCloudOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 110, - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "AzureCloud" - } - } - ] - } - }, - { - "name": "admin", - "addressPrefixes": [ - "10.0.1.0/27" - ], - "networkSecurityGroup": { - "name": "nsg-admin", - "securityRules": [ - { - "name": "Deny-hop-outbound", - "properties": { - "access": "Deny", - "direction": "Outbound", - "priority": 200, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "3389", - "22" - ], - "sourceAddressPrefix": "VirtualNetwork", - "destinationAddressPrefix": "*" - } - } - ] - } - } - ], + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable WAF for the deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + } + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enableScalability": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. An array of subnets to be created within the virtual network. Each subnet can have its own configuration and associated Network Security Group (NSG)." + "description": "Optional. Enable purge protection. Defaults to false." } }, "tags": { "type": "object", - "defaultValue": {}, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" + }, "description": "Optional. Tags to be applied to the resources." + }, + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" } }, - "logAnalyticsWorkspaceId": { + "existingLogAnalyticsWorkspaceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The resource ID of the Log Analytics Workspace to send diagnostic logs to." + "description": "Optional: Existing Log Analytics Workspace Resource ID" } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Use this parameter to use an existing AI project resource ID" + } + }, + "vmSize": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminUsername": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." } }, - "resourceSuffix": { + "createdBy": { "type": "string", + "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", "metadata": { - "description": "Required. Suffix for resource naming." + "description": "Optional. Tag, Created by user name." } } }, + "variables": { + "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", + "existingProjectResourceId": "[trim(parameters('existingFoundryProjectResourceId'))]", + "replicaRegionPairs": { + "australiaeast": "australiasoutheast", + "centralus": "westus", + "eastasia": "japaneast", + "eastus": "centralus", + "eastus2": "centralus", + "japaneast": "eastasia", + "northeurope": "westeurope", + "southeastasia": "eastasia", + "uksouth": "westeurope", + "westeurope": "northeurope" + }, + "replicaLocation": "[tryGet(variables('replicaRegionPairs'), parameters('location'))]", + "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", + "jumpboxVmName": "[take(format('vm-{0}', variables('solutionSuffix')), 15)]", + "dataCollectionRulesResourceName": "[format('dcr-{0}', variables('solutionSuffix'))]", + "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", + "dcrLogAnalyticsDestinationName": "[format('la-{0}-destination', variables('logAnalyticsWorkspaceResourceName'))]", + "privateDnsZones": [ + "privatelink.cognitiveservices.azure.com", + "privatelink.openai.azure.com", + "privatelink.services.ai.azure.com", + "privatelink.contentunderstanding.ai.azure.com", + "[format('privatelink.blob.{0}', environment().suffixes.storage)]", + "[format('privatelink.queue.{0}', environment().suffixes.storage)]", + "privatelink.mongo.cosmos.azure.com", + "privatelink.azconfig.io", + "privatelink.azurecr.io" + ], + "dnsZoneIndex": { + "cognitiveServices": 0, + "openAI": 1, + "aiServices": 2, + "contentUnderstanding": 3, + "storageBlob": 4, + "storageQueue": 5, + "cosmosDB": 6, + "appConfig": 7, + "containerRegistry": 8 + } + }, "resources": { - "nsgs": { - "copy": { - "name": "nsgs", - "count": "[length(parameters('subnets'))]", - "mode": "serial", - "batchSize": 1 - }, - "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('46d3xbcp.ptn.sa-contentprocessing.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroupTags": { + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", + "properties": { + "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" + } + }, + "virtualNetwork": { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.network-security-group.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", + "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "addressPrefixes": { + "value": [ + "10.0.0.0/8" + ] }, "location": { "value": "[parameters('location')]" }, - "securityRules": { - "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" - }, "tags": { "value": "[parameters('tags')]" }, + "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "resourceSuffix": { + "value": "[variables('solutionSuffix')]" + }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" } @@ -812,1596 +606,720 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7311263652424030280" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." + "version": "0.42.1.51946", + "templateHash": "10323079586505814920" + } }, "definitions": { - "securityRuleType": { + "subnetOutputType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the security rule." + "description": "The name of the subnet." } }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the subnet." + } + }, + "nsgName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The name of the associated NSG, if any." + } + }, + "nsgResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. The properties of the security rule." + "description": "The resource ID of the associated NSG, if any." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a security rule." + "description": "Subnet output type" } }, - "diagnosticSettingLogsOnlyType": { + "subnetType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Required. The name of the subnet." } }, - "logCategoriesAndGroups": { + "addressPrefixes": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "type": "string" }, - "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. Address prefixes for the subnet." } }, - "logAnalyticsDestinationType": { + "delegation": { "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Optional. Delegation for the subnet." } }, - "workspaceResourceId": { + "privateEndpointNetworkPolicies": { "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Private endpoint network policies." } }, - "storageAccountResourceId": { + "privateLinkServiceNetworkPolicies": { "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Private link service network policies." } }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", + "networkSecurityGroup": { + "$ref": "#/definitions/networkSecurityGroupType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. NSG configuration for the subnet." } }, - "eventHubName": { + "routeTableResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Route table resource ID." } }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. Service endpoint policies." } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. Service endpoints to enable." } }, - "notes": { - "type": "string", + "defaultOutboundAccess": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. Disable default outbound connectivity." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "Subnet configuration type" } }, - "roleAssignmentType": { + "networkSecurityGroupType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Required. The name of the NSG." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "securityRules": { + "type": "array", + "items": { + "type": "object" + }, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Required. Security rules for the NSG." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "NSG configuration type" } } }, "parameters": { - "name": { + "solutionName": { "type": "string", "metadata": { - "description": "Required. Name of the Network Security Group." + "description": "Solution name suffix used to derive the resource name." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Azure region for the resource." } }, - "securityRules": { + "addressPrefixes": { "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + "description": "Address prefixes for the virtual network." } }, - "diagnosticSettings": { + "subnets": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + "$ref": "#/definitions/subnetType" }, - "nullable": true, + "defaultValue": [ + { + "name": "backend", + "addressPrefixes": [ + "10.0.0.0/27" + ], + "networkSecurityGroup": { + "name": "nsg-backend", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "webserverfarm", + "addressPrefixes": [ + "10.0.4.0/27" + ], + "delegation": "Microsoft.Web/serverfarms", + "privateEndpointNetworkPolicies": "Enabled", + "privateLinkServiceNetworkPolicies": "Enabled", + "networkSecurityGroup": { + "name": "nsg-webserverfarm", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "administration", + "addressPrefixes": [ + "10.0.0.32/27" + ], + "networkSecurityGroup": { + "name": "nsg-administration", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "AzureBastionSubnet", + "addressPrefixes": [ + "10.0.0.64/26" + ], + "networkSecurityGroup": { + "name": "nsg-bastion", + "securityRules": [ + { + "name": "AllowGatewayManager", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2702, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "GatewayManager", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowHttpsInBound", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2703, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowSshRdpOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 100, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AllowAzureCloudOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 110, + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "AzureCloud" + } + } + ] + } + } + ], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Subnet configurations." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Tags to apply to the resources." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "logAnalyticsWorkspaceId": { + "type": "string", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Resource ID of the Log Analytics Workspace for diagnostics." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" - }, - "description": "Optional. Tags of the NSG resource." - }, - "nullable": true - }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "resourceSuffix": { + "type": "string", + "metadata": { + "description": "Suffix for resource naming." + } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "name": "[format('vnet-{0}', parameters('solutionName'))]" }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "nsgs": { + "copy": { + "name": "nsgs", + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "securityRules": { + "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7311263652424030280" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG)." + }, + "definitions": { + "securityRuleType": { + "type": "object", "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "properties": { + "type": "object", + "properties": { + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the security rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 4096, + "metadata": { + "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "metadata": { + "description": "Required. The properties of the security rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a security rule." } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.virtual-network.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "addressPrefixes": { - "value": "[parameters('addressPrefixes')]" - }, - "subnets": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('subnets'))]", - "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" - } - ] - }, - "diagnosticSettings": { - "value": [ - { - "name": "vnetDiagnostics", - "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", - "logCategoriesAndGroups": [ - { - "categoryGroup": "allLogs", - "enabled": true - } - ], - "metricCategories": [ - { - "category": "AllMetrics", - "enabled": true - } - ] - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "14370126050175308430" - }, - "name": "Virtual Networks", - "description": "This module deploys a Virtual Network (vNet)." - }, - "definitions": { - "peeringType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." - } - }, - "useRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - }, - "remotePeeringEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Deploy the outbound and the inbound peering." - } - }, - "remotePeeringName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." - } - }, - "remotePeeringAllowForwardedTraffic": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "remotePeeringAllowGatewayTransit": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "remotePeeringAllowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "remotePeeringDoNotVerifyRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." - } - }, - "remotePeeringUseRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." - } - }, - "ipamPoolPrefixAllocations": { - "type": "array", - "prefixItems": [ - { + }, + "diagnosticSettingLogsOnlyType": { "type": "object", "properties": { - "pool": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the IPAM pool." + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, "metadata": { - "description": "Required. The Resource ID of the IPAM pool." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "numberOfIpAddresses": { + "workspaceResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Number of IP addresses allocated from the pool." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } - } - } - } - ], - "items": false, - "nullable": true, - "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, - "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Virtual Network (vNet)." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." - } - }, - "ipamPoolNumberOfIpAddresses": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." - } - }, - "virtualNetworkBgpCommunity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The BGP community associated with the virtual network." - } - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An Array of subnets to deploy to the Virtual Network." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. DNS Servers associated to the Virtual Network." - } - }, - "ddosProtectionPlanResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." - } - }, - "peerings": { - "type": "array", - "items": { - "$ref": "#/definitions/peeringType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Virtual Network Peering configurations." - } - }, - "vnetEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." - } - }, - "vnetEncryptionEnforcement": { - "type": "string", - "defaultValue": "AllowUnencrypted", - "allowedValues": [ - "AllowUnencrypted", - "DropUnencrypted" - ], - "metadata": { - "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." - } - }, - "flowTimeoutInMinutes": { - "type": "int", - "defaultValue": 0, - "maxValue": 30, - "metadata": { - "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableVmProtection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." - } - }, - "enablePrivateEndpointVNetPolicies": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Basic", - "Disabled" - ], - "metadata": { - "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", - "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", - "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", - "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", - "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", - "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", - "enableVmProtection": "[parameters('enableVmProtection')]", - "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" - } - }, - "virtualNetwork_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_diagnosticSettings": { - "copy": { - "name": "virtualNetwork_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_roleAssignments": { - "copy": { - "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_subnets": { - "copy": { - "name": "virtualNetwork_subnets", - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualNetworkName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" - }, - "addressPrefix": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" - }, - "addressPrefixes": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" - }, - "ipamPoolPrefixAllocations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" - }, - "applicationGatewayIPConfigurations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" - }, - "delegation": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" - }, - "natGatewayResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" - }, - "networkSecurityGroupResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" - }, - "privateEndpointNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" - }, - "privateLinkServiceNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "routeTableResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" - }, - "serviceEndpointPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" - }, - "serviceEndpoints": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" - }, - "defaultOutboundAccess": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" - }, - "sharingScope": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "17113728662177315319" }, - "name": "Virtual Network Subnets", - "description": "This module deploys a Virtual Network Subnet." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -2473,7 +1391,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } @@ -2482,151 +1400,75 @@ "name": { "type": "string", "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "virtualNetworkName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + "description": "Required. Name of the Network Security Group." } }, - "addressPrefix": { + "location": { "type": "string", - "nullable": true, + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + "description": "Optional. Location for all resources." } }, - "ipamPoolPrefixAllocations": { + "securityRules": { "type": "array", "items": { - "type": "object" + "$ref": "#/definitions/securityRuleType" }, "nullable": true, "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." } }, - "routeTableResourceId": { - "type": "string", - "nullable": true, + "flushConnection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." } }, - "serviceEndpoints": { + "diagnosticSettings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" }, - "defaultValue": [], - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], "metadata": { - "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. The diagnostic settings of the service." } }, - "privateLinkServiceNetworkPolicies": { - "type": "string", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled" - ], "metadata": { - "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + "description": "Optional. The lock settings of the service." } }, - "addressPrefixes": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + "description": "Optional. Array of role assignments to create." } }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, + "tags": { + "type": "object", "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" + }, + "description": "Optional. Tags of the NSG resource." + }, + "nullable": true }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, @@ -2652,7 +1494,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2668,50 +1510,97 @@ } } }, - "virtualNetwork": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[parameters('virtualNetworkName')]" + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(coalesce(parameters('securityRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "properties": { + "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", + "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", + "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", + "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", + "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", + "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", + "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", + "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", + "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", + "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", + "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", + "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", + "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", + "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", + "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } }, - "subnet": { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "networkSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "serviceEndpoints", - "count": "[length(parameters('serviceEndpoints'))]", + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", "input": { - "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } ], - "addressPrefix": "[parameters('addressPrefix')]", - "addressPrefixes": "[parameters('addressPrefixes')]", - "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", - "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", - "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", - "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", - "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", - "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", - "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", - "sharingScope": "[parameters('sharingScope')]" - } - }, - "subnet_roleAssignments": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { "copy": { - "name": "subnet_roleAssignments", + "name": "networkSecurityGroup_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -2722,7 +1611,7 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "subnet" + "networkSecurityGroup" ] } }, @@ -2730,1928 +1619,2469 @@ "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the virtual network peering was deployed into." + "description": "The resource group the network security group was deployed into." }, "value": "[resourceGroup().name]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource ID of the network security group." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" }, - "addressPrefix": { + "name": { "type": "string", "metadata": { - "description": "The address prefix for the subnet." + "description": "The name of the network security group." }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "List of address prefixes for the subnet." - }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + "value": "[parameters('name')]" }, - "ipamPoolPrefixAllocations": { - "type": "array", + "location": { + "type": "string", "metadata": { - "description": "The IPAM pool prefix allocations for the subnet." + "description": "The location the resource was deployed into." }, - "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" } } } - }, - "dependsOn": [ - "virtualNetwork" - ] + } }, - "virtualNetwork_peering_local": { - "copy": { - "name": "virtualNetwork_peering_local", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" - }, + "virtualNetwork": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "localVnetName": { - "value": "[parameters('name')]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" - }, "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + "value": "[variables('name')]" }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + "location": { + "value": "[parameters('location')]" }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + "addressPrefixes": { + "value": "[parameters('addressPrefixes')]" }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + "subnets": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('subnets'))]", + "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" + } + ] }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + "diagnosticSettings": { + "value": [ + { + "name": "vnetDiagnostics", + "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs", + "enabled": true + } + ], + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "17951311301958631828" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." - } + "version": "0.41.2.15936", + "templateHash": "11272001757446231867" }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet)." }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork-peering.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "definitions": { + "peeringType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." } } - } - }, - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", - "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" - ] - }, - "virtualNetwork_peering_remote": { - "copy": { - "name": "virtualNetwork_peering_remote", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" - }, - "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", - "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "localVnetName": { - "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" - }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" - }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" - }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" - }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" - }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "17951311301958631828" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + "__bicep_export!": true } }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork-peering.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "subnetType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "prefixItems": [ + { + "type": "object", + "properties": { + "pool": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + } + }, + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + }, + "numberOfIpAddresses": { + "type": "string", + "metadata": { + "description": "Required. Number of IP addresses allocated from the pool." + } + } + } } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." } } - } - }, - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", - "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" + "__bicep_export!": true + } }, - "resourceId": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." + } + }, + "ipamPoolNumberOfIpAddresses": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + }, + "enablePrivateEndpointVNetPolicies": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Basic", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." + } } - } - } - }, - "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network." - }, - "value": "[parameters('name')]" - }, - "subnetNames": { - "type": "array", - "metadata": { - "description": "The names of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" - } - }, - "subnetResourceIds": { - "type": "array", - "metadata": { - "description": "The resource IDs of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "nsgs" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.name.value]" - }, - "resourceId": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetOutputType" - }, - "copy": { - "count": "[length(parameters('subnets'))]", - "input": { - "name": "[parameters('subnets')[copyIndex()].name]", - "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", - "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", - "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" - } - } - }, - "containersSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'containers'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'containers')], '')]" - }, - "backendSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" - }, - "bastionSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" - }, - "adminSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'admin'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'admin')], '')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "bastionHost": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('bastionHostName')]" - }, - "skuName": { - "value": "Standard" - }, - "location": { - "value": "[parameters('location')]" - }, - "virtualNetworkResourceId": { - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "publicIPAddressObject": { - "value": { - "name": "[format('pip-{0}', variables('bastionHostName'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7741601918225805390" - }, - "name": "Bastion Hosts", - "description": "This module deploys a Bastion Host." - }, - "definitions": { - "publicIPAddressObjectType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for the Public IP resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create for the Public IP resource." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable usage telemetry for the Public IP module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Idle timeout in minutes for the Public IP resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to apply to the Public IP resource." - }, - "nullable": true - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the Public IP resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure Bastion resource." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Shared services Virtual Network resource Id." - } - }, - "bastionSubnetPublicIpResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "publicIPAddressObject": { - "$ref": "#/definitions/publicIPAddressObjectType", - "defaultValue": { - "name": "[format('{0}-pip', parameters('name'))]" - }, - "metadata": { - "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Basic", - "allowedValues": [ - "Basic", - "Developer", - "Premium", - "Standard" - ], - "metadata": { - "description": "Optional. The SKU of this Bastion Host." - } - }, - "disableCopyPaste": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." - } - }, - "enableFileCopy": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." - } - }, - "enableIpConnect": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." - } - }, - "enableKerberos": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." - } - }, - "enableShareableLink": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." - } - }, - "enableSessionRecording": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." - } - }, - "enablePrivateOnlyBastion": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." - } - }, - "scaleUnits": { - "type": "int", - "defaultValue": 2, - "metadata": { - "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. The list of Availability zones to use for the zone-redundant resources." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "azureBastion": { - "type": "Microsoft.Network/bastionHosts", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[coalesce(parameters('tags'), createObject())]", - "sku": { - "name": "[parameters('skuName')]" - }, - "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", - "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", - "dependsOn": [ - "publicIPAddress" - ] - }, - "azureBastion_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_diagnosticSettings": { - "copy": { - "name": "azureBastion_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_roleAssignments": { - "copy": { - "name": "azureBastion_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "publicIPAddress": { - "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('publicIPAddressObject').name]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" - }, - "ipTags": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" - }, - "publicIPAddressVersion": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" - }, - "publicIPAllocationMethod": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" - }, - "publicIpPrefixResourceId": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" - }, - "skuName": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" - }, - "skuTier": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" - }, - "availabilityZones": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "16564959277054027786" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." - }, - "definitions": { - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]", + "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "ipamPoolPrefixAllocations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13992200806189615656" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + } + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "metadata": { + "description": "The IPAM pool prefix allocations for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + } + } } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "nsgs" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.name.value]" + }, + "resourceId": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetOutputType" + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex()].name]", + "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", + "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", + "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" } } }, - "roleAssignmentType": { + "backendSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" + }, + "webserverfarmSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" + }, + "administrationSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" + }, + "bastionSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "bastionHost": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('bastionHostName')]" + }, + "skuName": { + "value": "Standard" + }, + "location": { + "value": "[parameters('location')]" + }, + "virtualNetworkResourceId": { + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": { + "name": "[format('pip-{0}', variables('bastionHostName'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7741601918225805390" + }, + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host." + }, + "definitions": { + "publicIPAddressObjectType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Required. The name of the Public IP Address." } }, - "roleDefinitionIdOrName": { + "publicIpPrefixResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." } }, - "principalId": { + "publicIPAllocationMethod": { "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The public IP address allocation method." } }, - "principalType": { + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "IPv4", + "IPv6" ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. IP address version." } }, - "description": { - "type": "string", + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. The DNS settings of the public IP address." } }, - "condition": { + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. Name of a public IP address SKU." } }, - "conditionVersion": { + "skuTier": { "type": "string", "allowedValues": [ - "2.0" + "Global", + "Regional" ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Tier of a public IP address SKU." } }, - "delegatedManagedIdentityResourceId": { + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Location for the Public IP resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create for the Public IP resource." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the Public IP module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Idle timeout in minutes for the Public IP resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to apply to the Public IP resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the Public IP resource." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." + "__bicep_export!": true, + "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." } }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], "metadata": { - "description": "Optional. IP address version." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } } }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Bastion resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Shared services Virtual Network resource Id." + } + }, + "bastionSubnetPublicIpResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." } }, - "ipTags": { + "publicIPAddressObject": { + "$ref": "#/definitions/publicIPAddressObjectType", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/ipTagType" + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" }, "nullable": true, "metadata": { - "description": "Optional. The list of tags associated with the public IP address." + "description": "Optional. The diagnostic settings of the service." } }, "lock": { @@ -4663,93 +4093,113 @@ }, "skuName": { "type": "string", - "defaultValue": "Standard", + "defaultValue": "Basic", "allowedValues": [ "Basic", + "Developer", + "Premium", "Standard" ], "metadata": { - "description": "Optional. Name of a public IP address SKU." + "description": "Optional. The SKU of this Bastion Host." } }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Tier of a public IP address SKU." + "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." } }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, + "enableFileCopy": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." } }, - "deleteOption": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Delete", - "Detach" - ], + "enableIpConnect": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The delete option for the public IP address." + "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "enableKerberos": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." } }, - "enableTelemetry": { + "enableSessionRecording": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." + } + }, + "enablePrivateOnlyBastion": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." } }, - "idleTimeoutInMinutes": { + "scaleUnits": { "type": "int", - "defaultValue": 4, + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. The idle timeout of the public IP address." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" }, "description": "Optional. Tags of the resource." }, "nullable": true }, - "diagnosticSettings": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "availabilityZones": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "type": "int" }, - "nullable": true, + "defaultValue": [], + "allowedValues": [ + 1, + 2, + 3 + ], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. The list of Availability zones to use for the zone-redundant resources." } } }, @@ -4761,17 +4211,13 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { @@ -4779,7 +4225,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -4795,84 +4241,46 @@ } } }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", "apiVersion": "2025-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "tags": "[coalesce(parameters('tags'), createObject())]", "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" + "name": "[parameters('skuName')]" }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" - } + "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", + "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] }, - "publicIpAddress_lock": { + "azureBastion_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "publicIpAddress" + "azureBastion" ] }, - "publicIpAddress_roleAssignments": { + "azureBastion_diagnosticSettings": { "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "name": "azureBastion_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, { "name": "logs", "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", @@ -4891,9016 +4299,839 @@ "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "publicIpAddress" + "azureBastion" ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" - } - } - } - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the Azure Bastion was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name the Azure Bastion." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID the Azure Bastion." - }, - "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('azureBastion', '2025-01-01', 'full').location]" - }, - "ipConfAzureBastionSubnet": { - "type": "object", - "metadata": { - "description": "The Public IPconfiguration object for the AzureBastionSubnet." - }, - "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "jumpboxVM": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('jumpboxVmName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "computerName": { - "value": "[take(variables('jumpboxVmName'), 15)]" - }, - "osType": { - "value": "Windows" - }, - "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", - "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", - "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "patchMode": { - "value": "AutomaticByPlatform" - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "value": true - }, - "maintenanceConfigurationResourceId": { - "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" - }, - "enableAutomaticUpdates": { - "value": true - }, - "encryptionAtHost": { - "value": false - }, - "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", - "imageReference": { - "value": { - "publisher": "microsoft-dsvm", - "offer": "dsvm-win-2022", - "sku": "winserver-2022", - "version": "latest" - } - }, - "osDisk": { - "value": { - "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", - "caching": "ReadWrite", - "createOption": "FromImage", - "deleteOption": "Delete", - "diskSizeGB": 128, - "managedDisk": { - "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" - } - } - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-{0}', variables('jumpboxVmName'))]", - "tags": "[parameters('tags')]", - "deleteOption": "Delete", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", - "ipConfigurations": [ - { - "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", - "subnetResourceId": "[reference('virtualNetwork').outputs.adminSubnetResourceId.value]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" - } - ] - } - ] - }, - "extensionAadJoinConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]", - "typeHandlerVersion": "1.0", - "settings": { - "mdmId": "" - } - } - }, - "extensionAntiMalwareConfig": { - "value": { - "enabled": true, - "settings": { - "AntimalwareEnabled": "true", - "Exclusions": {}, - "RealtimeProtectionEnabled": "true", - "ScheduledScanSettings": { - "day": "7", - "isEnabled": "true", - "scanType": "Quick", - "time": "120" - } - }, - "tags": "[parameters('tags')]" - } - }, - "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", - "extensionNetworkWatcherAgentConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17174537341033050778" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." - }, - "definitions": { - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "diffDiskSettings": { - "type": "object", - "properties": { - "placement": { - "type": "string", - "allowedValues": [ - "CacheDisk", - "NvmeDisk", - "ResourceDisk" - ], - "metadata": { - "description": "Required. Specifies the ephemeral disk placement for the operating system disk." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing an OS disk." - } - }, - "dataDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." - } - }, - "diskIOPSReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." - } - }, - "diskMBpsReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" - }, - "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing a data disk." - } - }, - "publicKeyType": { - "type": "object", - "properties": { - "keyData": { - "type": "string", - "metadata": { - "description": "Required. Specifies the SSH public key data used to authenticate through ssh." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." - } - } - } - }, - "nicConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the NIC configuration." - } - }, - "nicSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The suffix to append to the NIC name." - } - }, - "enableIPForwarding": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify what happens to the network interface when the VM is deleted." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "metadata": { - "description": "Required. The IP configurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags of the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the NIC configuration." - } - }, - "imageReferenceType": { - "type": "object", - "properties": { - "communityGalleryImageId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." - } - }, - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the image reference." - } - }, - "offer": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The image publisher." - } - }, - "sku": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The SKU of the image." - } - }, - "version": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." - } - }, - "sharedGalleryImageId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the image reference." - } - }, - "planType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the plan." - } - }, - "product": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the product of the image from the marketplace." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher ID." - } - }, - "promotionCode": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The promotion code." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Specifies information about the marketplace image used to create the virtual machine." - } - }, - "autoShutDownConfigType": { - "type": "object", - "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the auto shutdown configuration." - } - }, - "timeZone": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." - } - }, - "dailyRecurrenceTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time of day the schedule will occur." - } - }, - "notificationSettings": { - "type": "object", - "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the notification settings." - } - }, - "emailRecipient": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." - } - }, - "notificationLocale": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." - } - }, - "webhookUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The webhook URL to which the notification will be sent." - } + "dependsOn": [ + "azureBastion" + ] }, - "timeInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The time in minutes before shutdown to send notifications." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the schedule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the configuration profile." - } - }, - "vaultSecretGroupType": { - "type": "object", - "properties": { - "sourceVault": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." - } - }, - "vaultCertificates": { - "type": "array", - "items": { - "type": "object", - "properties": { - "certificateStore": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." - } - }, - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of key vault references in SourceVault which contain certificates." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the set of certificates that should be installed onto the virtual machine." - } - }, - "vmGalleryApplicationType": { - "type": "object", - "properties": { - "packageReferenceId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." - } - }, - "configurationReference": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." - } - }, - "order": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the order in which the packages have to be installed." - } - }, - "tags": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies a passthrough value for more generic context." - } - }, - "treatFailureAsDeploymentFailure": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the gallery application that should be made available to the VM/VMSS." - } - }, - "additionalUnattendContentType": { - "type": "object", - "properties": { - "settingName": { - "type": "string", - "allowedValues": [ - "AutoLogon", - "FirstLogonCommands" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the name of the setting to which the content applies." - } - }, - "content": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." - } - }, - "winRMListenerType": { - "type": "object", - "properties": { - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "Http", - "Https" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the protocol of WinRM listener." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing a Windows Remote Management listener." - } - }, - "nicConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NIC configuration." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "Required. List of IP configurations of the NIC configuration." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the network interface configuration output." - } - }, - "extensionCustomScriptConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." - } - }, - "typeHandlerVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." - } - }, - "fileUris": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "protectedSettings": { - "type": "secureObject", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." - } - }, - "storageAccountName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." - } - }, - "storageAccountKey": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The access key of the storage account." - } - }, - "managedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." - } - }, - "fileUris": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. URLs for files to be downloaded." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "supressFailures": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a 'CustomScriptExtension' extension." - } - }, - "_1.applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } + "publicIPAddress": { + "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" + }, + "ipTags": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_2.ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_2.dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_2.ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_3.diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_3.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_3.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_4.publicIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Public IP Address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout in minutes." - } - }, - "lock": { - "$ref": "#/definitions/_3.lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the public IP address." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "ddosSettings": { - "$ref": "#/definitions/_2.ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "dnsSettings": { - "$ref": "#/definitions/_2.dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address version." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIpNameSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name suffix of the public IP address resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU tier of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], - "nullable": true, - "metadata": { - "description": "Optional. The zones of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "description": "The type for the public IP address configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer backend address pools." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application security groups." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application gateway backend address pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The gateway load balancer settings." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer inbound NAT rules." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address version." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The virtual network taps." - } - }, - "pipConfiguration": { - "$ref": "#/definitions/_4.publicIPConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The public IP address configuration." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "description": "The type for the IP configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "description": "The type for the network interface IP configuration output.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" - }, - "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." - }, - "nullable": true - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" - }, - "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." - }, - "nullable": true - }, - "plan": { - "$ref": "#/definitions/planType", - "nullable": true, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "type": "array", - "items": { - "$ref": "#/definitions/dataDiskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "hibernationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables hibernation capability on the VM." - } - }, - "adminUsername": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." - } - }, - "userData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "items": { - "$ref": "#/definitions/vaultSecretGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "evictionPolicy": { - "type": "string", - "defaultValue": "Deallocate", - "allowedValues": [ - "Deallocate", - "Delete" - ], - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "publicKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/publicKeyType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "galleryApplications": { - "type": "array", - "items": { - "$ref": "#/definitions/vmGalleryApplicationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." - } - }, - "availabilityZone": { - "type": "int", - "allowedValues": [ - -1, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." - } - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationType" - }, - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Recovery service vault name to add VMs to backup." - } - }, - "backupVaultResourceGroup": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." - } - }, - "backupPolicyName": { - "type": "string", - "defaultValue": "DefaultPolicy", - "metadata": { - "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." - } - }, - "autoShutdownConfig": { - "$ref": "#/definitions/autoShutDownConfigType", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for auto-shutdown." - } - }, - "maintenanceConfigurationResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The resource Id of a maintenance configuration for this VM." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAntiMalwareConfig": { - "type": "object", - "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", - "metadata": { - "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionMonitoringAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "dataCollectionRuleAssociations": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionDependencyAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNetworkWatcherAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "$ref": "#/definitions/extensionCustomScriptConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionHostPoolRegistration": { - "type": "secureObject", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "extensionGuestConfigurationExtension": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "guestConfiguration": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." - } - }, - "extensionGuestConfigurationExtensionProtectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "disablePasswordAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether password authentication should be disabled." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "enableHotpatching": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "items": { - "$ref": "#/definitions/additionalUnattendContentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRMListeners": { - "type": "array", - "items": { - "$ref": "#/definitions/winRMListenerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - }, - "capacityReservationGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." - } - }, - "networkAccessPolicy": { - "type": "string", - "defaultValue": "DenyAll", - "allowedValues": [ - "AllowAll", - "AllowPrivate", - "DenyAll" - ], - "metadata": { - "description": "Optional. Policy for accessing the disk via network." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Policy for controlling export on the disk." - } - } - }, - "variables": { - "copy": [ - { - "name": "publicKeysFormatted", - "count": "[length(parameters('publicKeys'))]", - "input": { - "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", - "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" - } - }, - { - "name": "additionalUnattendContentFormatted", - "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", - "input": { - "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", - "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", - "componentName": "Microsoft-Windows-Shell-Setup", - "passName": "OobeSystem" - } - }, - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "linuxConfiguration": { - "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", - "ssh": { - "publicKeys": "[variables('publicKeysFormatted')]" - }, - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" - }, - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", - "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", - "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", - "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", - "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", - "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", - "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", - "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", - "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", - "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", - "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", - "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", - "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" - }, - "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", - "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "managedDataDisks": { - "copy": { - "name": "managedDataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" - }, - "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", - "type": "Microsoft.Compute/disks", - "apiVersion": "2025-01-02", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", - "location": "[parameters('location')]", - "sku": { - "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" - }, - "properties": { - "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", - "creationData": { - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" - }, - "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", - "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "networkAccessPolicy": "[parameters('networkAccessPolicy')]" - }, - "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", - "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", - "plan": "[parameters('plan')]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", - "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", - "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", - "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", - "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", - "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", - "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", - "osType": "[parameters('osType')]", - "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", - "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", - "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", - "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", - "managedDisk": { - "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", - "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", - "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", - "hibernationEnabled": "[parameters('hibernationEnabled')]" - }, - "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" - } - } - ] - }, - "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", - "licenseType": "[parameters('licenseType')]", - "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" - }, - "dependsOn": [ - "managedDataDisks", - "vm_nic" - ] - }, - "vm_configurationAssignment": { - "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", - "type": "Microsoft.Maintenance/configurationAssignments", - "apiVersion": "2023-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[format('{0}assignment', parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", - "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_autoShutdownConfiguration": { - "condition": "[not(empty(parameters('autoShutdownConfig')))]", - "type": "Microsoft.DevTestLab/schedules", - "apiVersion": "2018-09-15", - "name": "[format('shutdown-computevm-{0}', parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", - "properties": { - "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", - "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "taskType": "ComputeVmShutdownTask", - "dailyRecurrence": { - "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" - }, - "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", - "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_dataCollectionRuleAssociations": { - "copy": { - "name": "vm_dataCollectionRuleAssociations", - "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" - }, - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Insights/dataCollectionRuleAssociations", - "apiVersion": "2024-03-11", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", - "properties": { - "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "cseIdentity": { - "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", - "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" - }, - "AzureWindowsBaseline": { - "condition": "[not(empty(parameters('guestConfiguration')))]", - "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", - "apiVersion": "2024-04-05", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", - "location": "[parameters('location')]", - "properties": { - "guestConfiguration": "[parameters('guestConfiguration')]" - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - }, - "vm_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_roleAssignments": { - "copy": { - "name": "vm_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" - }, - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableIPForwarding": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" - }, - "enableAcceleratedNetworking": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" - }, - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" - }, - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "lock": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "5982155361487304817" - } - }, - "definitions": { - "publicIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Public IP Address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout in minutes." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the public IP address." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address version." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIpNameSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name suffix of the public IP address resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU tier of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], - "nullable": true, - "metadata": { - "description": "Optional. The zones of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the public IP address configuration." - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer backend address pools." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application security groups." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application gateway backend address pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The gateway load balancer settings." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer inbound NAT rules." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address version." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The virtual network taps." - } - }, - "pipConfiguration": { - "$ref": "#/definitions/publicIPConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The public IP address configuration." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the IP configuration." - } - }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - } - }, - "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [] - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "networkInterface_publicIPAddresses": { - "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" - }, - "diagnosticSettings": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" - }, - "ddosSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" - }, - "publicIPAddressVersion": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" - }, - "publicIPAllocationMethod": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" - }, - "publicIpPrefixResourceId": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" - }, - "roleAssignments": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" - }, - "skuName": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" - }, - "skuTier": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "availabilityZones": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" - }, - "enableTelemetry": { - "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" - }, - "ipTags": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5349747633189946992" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" - }, - "description": "Optional. The public IP address allocation method." - }, - "defaultValue": "Static" - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" - }, - "description": "Optional. IP address version." - }, - "defaultValue": "IPv4" - }, - "dnsSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" - }, - "description": "Optional. The DNS settings of the public IP address." - }, - "nullable": true - }, - "ipTags": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" - }, - "description": "Optional. The list of tags associated with the public IP address." - }, - "nullable": true - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" - }, - "description": "Optional. Name of a public IP address SKU." - }, - "defaultValue": "Standard" - }, - "skuTier": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" - }, - "description": "Optional. Tier of a public IP address SKU." - }, - "defaultValue": "Regional" - }, - "ddosSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" - }, - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - }, - "nullable": true - }, - "deleteOption": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" - }, - "description": "Optional. The delete option for the public IP address." - }, - "nullable": true - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" - } - }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "272838238520810437" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface." - }, - "definitions": { - "networkInterfaceIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of load balancer backend address pools." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of references of LoadBalancerInboundNatRules." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the IP configuration is included." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Application Gateway Backend Address Pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The reference to gateway load balancer frontend IP." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Virtual Network Taps." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The resource ID of the deployed resource." - } - }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backend address pool." - } - }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the application security group." - } - }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the application gateway backend address pool." - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the sub resource." - } - }, - "inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the inbound NAT rule." - } - }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network tap." - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network interface IP configuration output." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationType" - }, - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "publicIp": { - "copy": { - "name": "publicIp", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", - "existing": true, - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2024-05-01", - "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", - "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", - "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", - "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", - "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", - "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", - "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", - "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed resource." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkInterface', '2024-05-01', 'full').location]" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "The list of IP configurations of the network interface." - }, - "copy": { - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", - "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", - "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" - } - } - } - } - } - }, - "dependsOn": [ - "networkInterface_publicIPAddresses" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the network interface." - }, - "value": "[reference('networkInterface').outputs.name.value]" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "The list of IP configurations of the network interface." - }, - "value": "[reference('networkInterface').outputs.ipConfigurations.value]" - } - } - } - } - }, - "vm_domainJoinExtension": { - "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_domainJoinExtension" - ] - }, - "vm_microsoftAntiMalwareExtension": { - "condition": "[parameters('extensionAntiMalwareConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": { - "value": "IaaSAntimalware" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_azureMonitorAgentExtension": { - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitor" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_microsoftAntiMalwareExtension" - ] - }, - "vm_dependencyAgentExtension": { - "condition": "[parameters('extensionDependencyAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitoring.DependencyAgent" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" - }, - "settings": { - "value": { - "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "vm_networkWatcherAgentExtension": { - "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.NetworkWatcher" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_dependencyAgentExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_networkWatcherAgentExtension" - ] - }, - "vm_customScriptExtension": { - "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" - }, - "provisionAfterExtensions": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettingsFromKeyVault": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" - }, - "settings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" - }, - "protectedSettings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "cseIdentity", - "vm" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_customScriptExtension" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - }, - "vm_hostPoolRegistrationExtension": { - "condition": "[parameters('extensionHostPoolRegistration').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.PowerShell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": { - "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", - "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", - "properties": { - "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", - "aadJoin": true - } - } - }, - "protectedSettings": { - "value": { - "properties": { - "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" - } - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_nvidiaGpuDriverWindowsExtension" - ] - }, - "vm_azureGuestConfigurationExtension": { - "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.GuestConfiguration" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" - }, - "protectedSettings": { - "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "16564959277054027786" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "deleteOption": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Delete", + "Detach" + ], + "metadata": { + "description": "Optional. The delete option for the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } } - }, - "forceUpdateTag": { + } + }, + "outputs": { + "resourceGroupName": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + "description": "The resource group the Azure Bastion was deployed into." }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" + "value": "[resourceGroup().name]" }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the extension." + "description": "The name the Azure Bastion." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the extension." + "description": "The resource ID the Azure Bastion." }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The name of the Resource Group the extension was created in." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('azureBastion', '2025-01-01', 'full').location]" }, - "location": { - "type": "string", + "ipConfAzureBastionSubnet": { + "type": "object", "metadata": { - "description": "The location the resource was deployed into." + "description": "The Public IPconfiguration object for the AzureBastionSubnet." }, - "value": "[reference('extension', '2024-11-01', 'full').location]" + "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" } } } }, "dependsOn": [ - "vm", - "vm_hostPoolRegistrationExtension" + "logAnalyticsWorkspace", + "virtualNetwork" ] }, - "vm_backup": { - "condition": "[not(empty(parameters('backupVaultName')))]", + "jumpboxVM": { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", - "resourceGroup": "[parameters('backupVaultResourceGroup')]", + "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -13908,1551 +5139,2075 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + "value": "[variables('jumpboxVmName')]" }, "location": { "value": "[parameters('location')]" }, - "policyId": { - "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "computerName": { + "value": "[take(variables('jumpboxVmName'), 15)]" + }, + "osType": { + "value": "Windows" + }, + "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", + "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", + "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": true }, - "protectedItemType": { - "value": "Microsoft.Compute/virtualMachines" + "maintenanceConfigurationResourceId": { + "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", + "imageReference": { + "value": { + "publisher": "microsoft-dsvm", + "offer": "dsvm-win-2022", + "sku": "winserver-2022", + "version": "latest" + } + }, + "osDisk": { + "value": { + "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" + } + } + }, + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-{0}', variables('jumpboxVmName'))]", + "tags": "[parameters('tags')]", + "deleteOption": "Delete", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", + "ipConfigurations": [ + { + "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", + "subnetResourceId": "[reference('virtualNetwork').outputs.administrationSubnetResourceId.value]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" + } + ] + } + ] }, - "protectionContainerName": { - "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]", + "typeHandlerVersion": "1.0", + "settings": { + "mdmId": "" + } + } }, - "recoveryVaultName": { - "value": "[parameters('backupVaultName')]" + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": {}, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + }, + "tags": "[parameters('tags')]" + } }, - "sourceResourceId": { - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]" + } } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "17448691641471706096" + "templateHash": "17174537341033050778" }, - "name": "Recovery Service Vaults Protection Container Protected Item", - "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." }, - "parameters": { - "name": { - "type": "string", + "definitions": { + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "diffDiskSettings": { + "type": "object", + "properties": { + "placement": { + "type": "string", + "allowedValues": [ + "CacheDisk", + "NvmeDisk", + "ResourceDisk" + ], + "metadata": { + "description": "Required. Specifies the ephemeral disk placement for the operating system disk." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + }, "metadata": { - "description": "Required. Name of the resource." + "__bicep_export!": true, + "description": "The type describing an OS disk." } }, - "protectionContainerName": { - "type": "string", + "dataDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" + }, + "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." + }, + "nullable": true + } + }, "metadata": { - "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type describing a data disk." } }, - "recoveryVaultName": { - "type": "string", + "publicKeyType": { + "type": "object", + "properties": { + "keyData": { + "type": "string", + "metadata": { + "description": "Required. Specifies the SSH public key data used to authenticate through ssh." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." + } + } + } + }, + "nicConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the NIC configuration." + } + }, + "nicSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The suffix to append to the NIC name." + } + }, + "enableIPForwarding": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify what happens to the network interface when the VM is deleted." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "metadata": { + "description": "Required. The IP configurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for the NIC configuration." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "imageReferenceType": { + "type": "object", + "properties": { + "communityGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." + } + }, + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource Id of the image reference." + } + }, + "offer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The image publisher." + } + }, + "sku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SKU of the image." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." + } + }, + "sharedGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." + } + } + }, "metadata": { - "description": "Optional. Location for all resources." + "__bicep_export!": true, + "description": "The type describing the image reference." } }, - "protectedItemType": { - "type": "string", - "allowedValues": [ - "AzureFileShareProtectedItem", - "AzureVmWorkloadSAPAseDatabase", - "AzureVmWorkloadSAPHanaDatabase", - "AzureVmWorkloadSQLDatabase", - "DPMProtectedItem", - "GenericProtectedItem", - "MabFileFolderProtectedItem", - "Microsoft.ClassicCompute/virtualMachines", - "Microsoft.Compute/virtualMachines", - "Microsoft.Sql/servers/databases" - ], + "planType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the plan." + } + }, + "product": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the product of the image from the marketplace." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher ID." + } + }, + "promotionCode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The promotion code." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Specifies information about the marketplace image used to create the virtual machine." + } + }, + "autoShutDownConfigType": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the auto shutdown configuration." + } + }, + "timeZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." + } + }, + "dailyRecurrenceTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time of day the schedule will occur." + } + }, + "notificationSettings": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the notification settings." + } + }, + "emailRecipient": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." + } + }, + "notificationLocale": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + } + }, + "webhookUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The webhook URL to which the notification will be sent." + } + }, + "timeInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The time in minutes before shutdown to send notifications." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the schedule." + } + } + }, "metadata": { - "description": "Required. The backup item type." + "__bicep_export!": true, + "description": "The type describing the configuration profile." } }, - "policyId": { - "type": "string", + "vaultSecretGroupType": { + "type": "object", + "properties": { + "sourceVault": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." + } + }, + "vaultCertificates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "certificateStore": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + } + }, + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of key vault references in SourceVault which contain certificates." + } + } + }, "metadata": { - "description": "Required. ID of the backup policy with which this item is backed up." + "__bicep_export!": true, + "description": "The type describing the set of certificates that should be installed onto the virtual machine." } }, - "sourceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource to back up." - } - } - }, - "resources": [ - { - "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", - "apiVersion": "2025-02-01", - "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", - "location": "[parameters('location')]", + "vmGalleryApplicationType": { + "type": "object", "properties": { - "protectedItemType": "[parameters('protectedItemType')]", - "policyId": "[parameters('policyId')]", - "sourceResourceId": "[parameters('sourceResourceId')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the protected item was created in." + "packageReferenceId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." + } + }, + "configurationReference": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." + } + }, + "order": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the order in which the packages have to be installed." + } + }, + "tags": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies a passthrough value for more generic context." + } + }, + "treatFailureAsDeploymentFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." + } + } }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the protected item." - }, - "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + "__bicep_export!": true, + "description": "The type describing the gallery application that should be made available to the VM/VMSS." + } }, - "name": { - "type": "string", - "metadata": { - "description": "The Name of the protected item." + "additionalUnattendContentType": { + "type": "object", + "properties": { + "settingName": { + "type": "string", + "allowedValues": [ + "AutoLogon", + "FirstLogonCommands" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the setting to which the content applies." + } + }, + "content": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." + } + } }, - "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2024-07-01', 'full').location]" - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationOutputType" - }, - "metadata": { - "description": "The list of NIC configurations of the virtual machine." - }, - "copy": { - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", - "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" - } - } - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "maintenanceConfiguration", - "virtualNetwork", - "windowsVmDataCollectionRules" - ] - }, - "maintenanceConfiguration": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('mc-{0}', variables('jumpboxVmName'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "extensionProperties": { - "value": { - "InGuestPatchMode": "User" - } - }, - "maintenanceScope": { - "value": "InGuestPatch" - }, - "maintenanceWindow": { - "value": { - "startDateTime": "2024-06-16 00:00", - "duration": "03:55", - "timeZone": "W. Europe Standard Time", - "recurEvery": "1Day" - } - }, - "visibility": { - "value": "Custom" - }, - "installPatches": { - "value": { - "rebootSetting": "IfRequired", - "windowsParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - }, - "linuxParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - } - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14895287194406877557" - }, - "name": "Maintenance Configurations", - "description": "This module deploys a Maintenance Configuration." - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Maintenance Configuration Name." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "extensionProperties": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" - }, - "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." - }, - "defaultValue": {} - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "maintenanceScope": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" - }, - "description": "Optional. Gets or sets maintenanceScope of the configuration." - }, - "defaultValue": "Host" - }, - "maintenanceWindow": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" - }, - "description": "Optional. Definition of a MaintenanceWindow." - }, - "defaultValue": {} - }, - "namespace": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Gets or sets namespace of the resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" - }, - "description": "Optional. Gets or sets tags of the resource." - }, - "nullable": true - }, - "visibility": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" - }, - "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." - }, - "nullable": true - }, - "installPatches": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" - }, - "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." - }, - "defaultValue": {} - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "maintenanceConfiguration": { - "type": "Microsoft.Maintenance/maintenanceConfigurations", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "extensionProperties": "[parameters('extensionProperties')]", - "maintenanceScope": "[parameters('maintenanceScope')]", - "maintenanceWindow": "[parameters('maintenanceWindow')]", - "namespace": "[parameters('namespace')]", - "visibility": "[parameters('visibility')]", - "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" - } - }, - "maintenanceConfiguration_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - }, - "maintenanceConfiguration_roleAssignments": { - "copy": { - "name": "maintenanceConfiguration_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Maintenance Configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Maintenance Configuration." - }, - "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Maintenance Configuration was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the Maintenance Configuration was created in." - }, - "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" - } - } - } - } - }, - "windowsVmDataCollectionRules": { - "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('dataCollectionRulesResourceName')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "location": { - "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" - }, - "dataCollectionRuleProperties": { - "value": { - "kind": "Windows", - "dataSources": { - "performanceCounters": [ - { - "streams": [ - "Microsoft-Perf" - ], - "samplingFrequencyInSeconds": 60, - "counterSpecifiers": [ - "\\Processor Information(_Total)\\% Processor Time", - "\\Processor Information(_Total)\\% Privileged Time", - "\\Processor Information(_Total)\\% User Time", - "\\Processor Information(_Total)\\Processor Frequency", - "\\System\\Processes", - "\\Process(_Total)\\Thread Count", - "\\Process(_Total)\\Handle Count", - "\\System\\System Up Time", - "\\System\\Context Switches/sec", - "\\System\\Processor Queue Length", - "\\Memory\\% Committed Bytes In Use", - "\\Memory\\Available Bytes", - "\\Memory\\Committed Bytes", - "\\Memory\\Cache Bytes", - "\\Memory\\Pool Paged Bytes", - "\\Memory\\Pool Nonpaged Bytes", - "\\Memory\\Pages/sec", - "\\Memory\\Page Faults/sec", - "\\Process(_Total)\\Working Set", - "\\Process(_Total)\\Working Set - Private", - "\\LogicalDisk(_Total)\\% Disk Time", - "\\LogicalDisk(_Total)\\% Disk Read Time", - "\\LogicalDisk(_Total)\\% Disk Write Time", - "\\LogicalDisk(_Total)\\% Idle Time", - "\\LogicalDisk(_Total)\\Disk Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Transfers/sec", - "\\LogicalDisk(_Total)\\Disk Reads/sec", - "\\LogicalDisk(_Total)\\Disk Writes/sec", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", - "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", - "\\LogicalDisk(_Total)\\% Free Space", - "\\LogicalDisk(_Total)\\Free Megabytes", - "\\Network Interface(*)\\Bytes Total/sec", - "\\Network Interface(*)\\Bytes Sent/sec", - "\\Network Interface(*)\\Bytes Received/sec", - "\\Network Interface(*)\\Packets/sec", - "\\Network Interface(*)\\Packets Sent/sec", - "\\Network Interface(*)\\Packets Received/sec", - "\\Network Interface(*)\\Packets Outbound Errors", - "\\Network Interface(*)\\Packets Received Errors" - ], - "name": "perfCounterDataSource60" - } - ], - "windowsEventLogs": [ - { - "name": "SecurityAuditEvents", - "streams": [ - "Microsoft-Event" - ], - "xPathQueries": [ - "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" - ] - } - ] - }, - "destinations": { - "logAnalytics": [ - { - "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", - "name": "[variables('dcrLogAnalyticsDestinationName')]" - } - ] - }, - "dataFlows": [ - { - "streams": [ - "Microsoft-Perf" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Perf" - }, - { - "streams": [ - "Microsoft-Event" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Event" - } - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2441324888126124697" - }, - "name": "Data Collection Rules", - "description": "This module deploys a Data Collection Rule." - }, - "definitions": { - "dataCollectionRulePropertiesType": { - "type": "object", - "discriminator": { - "propertyName": "kind", - "mapping": { - "Linux": { - "$ref": "#/definitions/linuxDcrPropertiesType" - }, - "Windows": { - "$ref": "#/definitions/windowsDcrPropertiesType" - }, - "All": { - "$ref": "#/definitions/allPlatformsDcrPropertiesType" - }, - "AgentSettings": { - "$ref": "#/definitions/agentSettingsDcrPropertiesType" - }, - "Direct": { - "$ref": "#/definitions/directDcrPropertiesType" - }, - "WorkspaceTransforms": { - "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" - }, - "PlatformTelemetry": { - "$ref": "#/definitions/platformTelemetryDcrPropertiesType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." - } - }, - "linuxDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Linux" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Linux' data collection rule." - } - }, - "windowsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Windows" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + "metadata": { + "__bicep_export!": true, + "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." + } }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "winRMListenerType": { + "type": "object", + "properties": { + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Http", + "Https" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the protocol of WinRM listener." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a Windows Remote Management listener." + } }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "nicConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NIC configuration." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "Required. List of IP configurations of the NIC configuration." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the network interface configuration output." + } }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + "extensionCustomScriptConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." + } + }, + "typeHandlerVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "protectedSettings": { + "type": "secureObject", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." + } + }, + "storageAccountName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." + } + }, + "storageAccountKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The access key of the storage account." + } + }, + "managedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "supressFailures": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a 'CustomScriptExtension' extension." + } }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Windows' data collection rule." - } - }, - "allPlatformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "All" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + "_1.applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "_1.applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "_1.backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + "_1.inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the data collection rule of the kind 'All'." - } - }, - "agentSettingsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "AgentSettings" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "agentSettings": { - "$ref": "#/definitions/agentSettingsType", - "metadata": { - "description": "Required. Agent settings used to modify agent behavior on a given host." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'AgentSettings' data collection rule." - } - }, - "agentSettingsType": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "$ref": "#/definitions/agentSettingType" - }, - "metadata": { - "description": "Required. All the settings that are applicable to the logs agent (AMA)." - } - } - }, - "metadata": { - "description": "The type for the agent settings." - } - }, - "agentSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "MaxDiskQuotaInMB", - "UseTimeReceivedForForwardedEvents" - ], - "metadata": { - "description": "Required. The name of the agent setting." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. The value of the agent setting." - } - } - }, - "metadata": { - "description": "The type for the (single) agent setting." - } - }, - "directDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Direct" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "_1.subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "_2.ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + "_2.dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } }, - "description": "Required. Declaration of custom streams used in this rule." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Direct' data collection rule." - } - }, - "workspaceTransformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "WorkspaceTransforms" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "_2.ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } }, - "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "_3.diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." - } - }, - "platformTelemetryDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "PlatformTelemetry" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "dataSources": { - "type": "object", - "properties": { - "platformTelemetry": { - "type": "array", + "_3.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_4.publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/_3.lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/_2.ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/_2.dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true }, - "description": "Required. The list of platform telemetry configurations." - } - } - }, - "metadata": { - "description": "Required. Specification of data sources that will be collected." - } - }, - "destinations": { - "type": "object", - "properties": { - "logAnalytics": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } }, - "description": "Optional. The list of Log Analytics destinations." + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } }, - "nullable": true - }, - "storageAccounts": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + "description": "The type for the public IP address configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The list of Storage Account destinations." + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, - "nullable": true - }, - "eventHubs": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/_4.publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true }, - "description": "Optional. The list of Event Hub destinations." + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } }, - "nullable": true - } - }, - "metadata": { - "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "metadata": { + "description": "The type for the IP configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } }, - "description": "Required. The specification of data flows." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the data collection rule. The name is case insensitive." - } - }, - "dataCollectionRuleProperties": { - "$ref": "#/definitions/dataCollectionRulePropertiesType", - "metadata": { - "description": "Required. The kind of data collection rule." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "dataCollectionRule": { - "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "kind": "[parameters('dataCollectionRuleProperties').kind]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRuleAll": { - "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRule_conditionalScopeLock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", - "lock": { - "value": "[parameters('lock')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2876136109547890997" - } - }, - "definitions": { "lockType": { "type": "object", "properties": { @@ -15460,38 +7215,638 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." } }, - "kind": { + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "description": "The type for the network interface IP configuration output.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { "type": "string", "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. The principal type of the assigned principal ID." } }, - "notes": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" } } } }, "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" + }, + "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." + }, + "nullable": true + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" + }, + "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." + }, + "nullable": true + }, + "plan": { + "$ref": "#/definitions/planType", + "nullable": true, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "type": "array", + "items": { + "$ref": "#/definitions/dataDiskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "hibernationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables hibernation capability on the VM." + } + }, + "adminUsername": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." + } + }, + "userData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "items": { + "$ref": "#/definitions/vaultSecretGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "Deallocate", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "publicKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/publicKeyType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "galleryApplications": { + "type": "array", + "items": { + "$ref": "#/definitions/vmGalleryApplicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." + } + }, + "availabilityZone": { + "type": "int", + "allowedValues": [ + -1, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." + } + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationType" + }, + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Recovery service vault name to add VMs to backup." + } + }, + "backupVaultResourceGroup": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "DefaultPolicy", + "metadata": { + "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + } + }, + "autoShutdownConfig": { + "$ref": "#/definitions/autoShutDownConfigType", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for auto-shutdown." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource Id of a maintenance configuration for this VM." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "dataCollectionRuleAssociations": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "$ref": "#/definitions/extensionCustomScriptConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionHostPoolRegistration": { + "type": "secureObject", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "extensionGuestConfigurationExtension": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "guestConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." + } + }, + "extensionGuestConfigurationExtensionProtectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, "lock": { "$ref": "#/definitions/lockType", "nullable": true, @@ -15499,212 +7854,255 @@ "description": "Optional. The lock settings of the service." } }, - "dataCollectionRuleName": { + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "osType": { "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], "metadata": { - "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + "description": "Required. The chosen OS type." } - } - }, - "resources": { - "dataCollectionRule": { - "existing": true, - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('dataCollectionRuleName')]" }, - "dataCollectionRule_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + "disablePasswordAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether password authentication should be disabled." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." } - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - }, - "dataCollectionRule_roleAssignments": { - "copy": { - "name": "dataCollectionRule_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", - "name": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "14634305923902101494" }, - "name": "Resource-scoped role assignment", - "description": "This module deploys a Role Assignment for a specific resource." - }, - "parameters": { - "resourceId": { + "patchMode": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], "metadata": { - "description": "Required. The scope for the role assignment, fully qualified resourceId." + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." } }, - "name": { + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { "type": "string", - "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], "metadata": { - "description": "Optional. The unique guid name for the role assignment." + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." } }, - "roleDefinitionId": { + "patchAssessmentMode": { "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "enableHotpatching": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The role definition ID for the role assignment." + "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." } }, - "roleName": { + "timeZone": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. The name for the role, used for logging." + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." } }, - "principalId": { - "type": "string", + "additionalUnattendContent": { + "type": "array", + "items": { + "$ref": "#/definitions/additionalUnattendContentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRMListeners": { + "type": "array", + "items": { + "$ref": "#/definitions/winRMListenerType" + }, + "nullable": true, "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." } }, - "principalType": { + "configurationProfile": { "type": "string", "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." } }, - "description": { + "capacityReservationGroupResourceId": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. The description of role assignment." + "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "networkAccessPolicy": { + "type": "string", + "defaultValue": "DenyAll", + "allowedValues": [ + "AllowAll", + "AllowPrivate", + "DenyAll" + ], "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Policy for accessing the disk via network." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Policy for controlling export on the disk." } } }, "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string" - }, - "name": { - "type": "string" - }, - "roleDefinitionId": { - "type": "string" - }, - "principalId": { - "type": "string" - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string" + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" } }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "principalType": "[[parameters('principalType')]", - "description": "[[parameters('description')]" - } - } - ], - "outputs": { - "roleAssignmentId": { - "type": "string", - "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + { + "name": "additionalUnattendContentFormatted", + "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", + "input": { + "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", + "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", + "componentName": "Microsoft-Windows-Shell-Setup", + "passName": "OobeSystem" } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } - } + ], + "enableReferencedModulesTelemetry": false, + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", + "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" + }, + "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", + "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" }, - "resources": [ - { + "resources": { + "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -15712,2135 +8110,6082 @@ "contentVersion": "1.0.0.0", "resources": [], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "managedDataDisks": { + "copy": { + "name": "managedDataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" + }, + "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", + "type": "Microsoft.Compute/disks", + "apiVersion": "2025-01-02", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", + "location": "[parameters('location')]", + "sku": { + "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" + }, + "properties": { + "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", + "creationData": { + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" + }, + "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", + "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "networkAccessPolicy": "[parameters('networkAccessPolicy')]" + }, + "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", + "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", + "plan": "[parameters('plan')]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", + "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", + "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", + "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", + "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", + "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", + "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", + "osType": "[parameters('osType')]", + "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", + "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", + "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", + "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", + "managedDisk": { + "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", + "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", + "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", + "hibernationEnabled": "[parameters('hibernationEnabled')]" + }, + "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" + } + } + ] + }, + "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", + "licenseType": "[parameters('licenseType')]", + "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" + }, + "dependsOn": [ + "managedDataDisks", + "vm_nic" + ] + }, + "vm_configurationAssignment": { + "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", + "type": "Microsoft.Maintenance/configurationAssignments", + "apiVersion": "2023-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[format('{0}assignment', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", + "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_autoShutdownConfiguration": { + "condition": "[not(empty(parameters('autoShutdownConfig')))]", + "type": "Microsoft.DevTestLab/schedules", + "apiVersion": "2018-09-15", + "name": "[format('shutdown-computevm-{0}', parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", + "properties": { + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", + "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "taskType": "ComputeVmShutdownTask", + "dailyRecurrence": { + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" + }, + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_dataCollectionRuleAssociations": { + "copy": { + "name": "vm_dataCollectionRuleAssociations", + "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" + }, + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2024-03-11", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", + "properties": { + "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "cseIdentity": { + "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", + "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" + }, + "AzureWindowsBaseline": { + "condition": "[not(empty(parameters('guestConfiguration')))]", + "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", + "apiVersion": "2024-04-05", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", + "location": "[parameters('location')]", + "properties": { + "guestConfiguration": "[parameters('guestConfiguration')]" + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + }, + "vm_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_roleAssignments": { + "copy": { + "name": "vm_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" + }, + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" + }, + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" + }, + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "lock": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "5982155361487304817" + } + }, + "definitions": { + "publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the public IP address configuration." + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the IP configuration." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" + }, + "enableTelemetry": { + "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" + }, + "ipTags": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5349747633189946992" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" + }, + "description": "Optional. The public IP address allocation method." + }, + "defaultValue": "Static" + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" + }, + "description": "Optional. IP address version." + }, + "defaultValue": "IPv4" + }, + "dnsSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" + }, + "description": "Optional. The DNS settings of the public IP address." + }, + "nullable": true + }, + "ipTags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" + }, + "description": "Optional. The list of tags associated with the public IP address." + }, + "nullable": true + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" + }, + "description": "Optional. Name of a public IP address SKU." + }, + "defaultValue": "Standard" + }, + "skuTier": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" + }, + "description": "Optional. Tier of a public IP address SKU." + }, + "defaultValue": "Regional" + }, + "ddosSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" + }, + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + }, + "nullable": true + }, + "deleteOption": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" + }, + "description": "Optional. The delete option for the public IP address." + }, + "nullable": true + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "272838238520810437" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface." + }, + "definitions": { + "networkInterfaceIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of load balancer backend address pools." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of references of LoadBalancerInboundNatRules." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the IP configuration is included." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Application Gateway Backend Address Pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The reference to gateway load balancer frontend IP." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Virtual Network Taps." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The resource ID of the deployed resource." + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backend address pool." + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application security group." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application gateway backend address pool." + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the sub resource." + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the inbound NAT rule." + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network tap." + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network interface IP configuration output." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationType" + }, + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "publicIp": { + "copy": { + "name": "publicIp", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", + "existing": true, + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", + "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", + "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", + "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", + "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", + "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", + "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", + "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2024-05-01', 'full').location]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "copy": { + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", + "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", + "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" + } + } + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the network interface." + }, + "value": "[reference('networkInterface').outputs.name.value]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "value": "[reference('networkInterface').outputs.ipConfigurations.value]" } } } } }, - { + "vm_domainJoinExtension": { + "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", "properties": { - "mode": "Incremental", "expressionEvaluationOptions": { - "scope": "Outer" + "scope": "inner" }, - "template": "[variables('$fxv#0')]", + "mode": "Incremental", "parameters": { - "scope": { - "value": "[parameters('resourceId')]" + "virtualMachineName": { + "value": "[parameters('name')]" }, "name": { - "value": "[parameters('name')]" + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" }, - "roleDefinitionId": { - "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + "location": { + "value": "[parameters('location')]" }, - "principalId": { - "value": "[parameters('principalId')]" + "publisher": { + "value": "Microsoft.Compute" }, - "principalType": { - "value": "[parameters('principalType')]" + "type": { + "value": "JsonADDomainExtension" }, - "description": { - "value": "[parameters('description')]" + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } } - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[parameters('name')]" - }, - "roleName": { - "type": "string", - "metadata": { - "description": "The name for the role, used for logging." - }, - "value": "[parameters('roleName')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the dataCollectionRule was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" - }, - "endpoints": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", - "output": true - }, - "description": "The endpoints of the dataCollectionRule, if created." - }, - "nullable": true, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" - }, - "immutableId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The ImmutableId of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmPrivateDnsZones": { - "copy": { - "name": "avmPrivateDnsZones", - "count": "[length(variables('privateDnsZones'))]", - "mode": "serial", - "batchSize": 5 - }, - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZones')[copyIndex()]]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "virtualNetworkLinks": { - "value": [ - { - "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18337341331267624582" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone." - }, - "definitions": { - "aType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" - }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the A record." - } - }, - "aaaaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the AAAA record." - } - }, - "cnameType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. The CNAME record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the CNAME record." - } - }, - "mxType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the MX record." - } - }, - "ptrType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the PTR record." - } - }, - "soaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "soaRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" - }, - "description": "Optional. The SOA record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SOA record." - } - }, - "srvType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "srvRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" - }, - "description": "Optional. The list of SRV records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SRV record." - } - }, - "txtType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "txtRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the TXT record." - } - }, - "virtualNetworkLinkType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 1, - "maxLength": 80, - "metadata": { - "description": "Optional. The resource name." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the virtual network to link." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Region where the resource lives." - } - }, - "registrationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_domainJoinExtension" + ] }, - "description": "Optional. Resource tags." - }, - "nullable": true - }, - "resolutionPolicy": { - "type": "string", - "allowedValues": [ - "Default", - "NxDomainRedirect" - ], - "nullable": true, - "metadata": { - "description": "Optional. The resolution type of the private-dns-zone fallback machanism." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network link." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "a": { - "type": "array", - "items": { - "$ref": "#/definitions/aType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of A records." - } - }, - "aaaa": { - "type": "array", - "items": { - "$ref": "#/definitions/aaaaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of AAAA records." - } - }, - "cname": { - "type": "array", - "items": { - "$ref": "#/definitions/cnameType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of CNAME records." - } - }, - "mx": { - "type": "array", - "items": { - "$ref": "#/definitions/mxType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of MX records." - } - }, - "ptr": { - "type": "array", - "items": { - "$ref": "#/definitions/ptrType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of PTR records." - } - }, - "soa": { - "type": "array", - "items": { - "$ref": "#/definitions/soaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SOA records." - } - }, - "srv": { - "type": "array", - "items": { - "$ref": "#/definitions/srvType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SRV records." - } - }, - "txt": { - "type": "array", - "items": { - "$ref": "#/definitions/txtType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of TXT records." - } - }, - "virtualNetworkLinks": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkLinkType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_roleAssignments": { - "copy": { - "name": "privateDnsZone_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_A": { - "copy": { - "name": "privateDnsZone_A", - "count": "[length(coalesce(parameters('a'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" - }, - "aRecords": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7372385900111002873" + "vm_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] }, - "name": "Private DNS Zone A record", - "description": "This module deploys a Private DNS Zone A record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" } }, - "condition": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } + } + }, + "dependsOn": [ + "vm", + "vm_microsoftAntiMalwareExtension" + ] + }, + "vm_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, + "settings": { + "value": { + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the A record." - } + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + "vm_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" + } }, - "description": "Optional. The metadata attached to the record set." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "vm", + "vm_dependencyAgentExtension" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "A": { - "type": "Microsoft.Network/privateDnsZones/A", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aRecords": "[parameters('aRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "A_roleAssignments": { - "copy": { - "name": "A_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "A" + "vm", + "vm_networkWatcherAgentExtension" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed A record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed A record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed A record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_AAAA": { - "copy": { - "name": "privateDnsZone_AAAA", - "count": "[length(coalesce(parameters('aaaa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" - }, - "aaaaRecords": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14405855828972373002" }, - "name": "Private DNS Zone AAAA record", - "description": "This module deploys a Private DNS Zone AAAA record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_customScriptExtension": { + "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" + }, + "provisionAfterExtensions": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettingsFromKeyVault": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" + }, + "settings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" + }, + "protectedSettings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the AAAA record." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "cseIdentity", + "vm" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "AAAA": { - "type": "Microsoft.Network/privateDnsZones/AAAA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aaaaRecords": "[parameters('aaaaRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "AAAA_roleAssignments": { - "copy": { - "name": "AAAA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "AAAA" + "vm", + "vm_customScriptExtension" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AAAA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed AAAA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed AAAA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_CNAME": { - "copy": { - "name": "privateDnsZone_CNAME", - "count": "[length(coalesce(parameters('cname'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" - }, - "cnameRecord": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13818627461335065928" }, - "name": "Private DNS Zone CNAME record", - "description": "This module deploys a Private DNS Zone CNAME record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the CNAME record." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. A CNAME record." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_hostPoolRegistrationExtension": { + "condition": "[parameters('extensionHostPoolRegistration').enabled]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.PowerShell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", + "properties": { + "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", + "aadJoin": true + } + } + }, + "protectedSettings": { + "value": { + "properties": { + "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" + } + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "CNAME": { - "type": "Microsoft.Network/privateDnsZones/CNAME", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "cnameRecord": "[parameters('cnameRecord')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "CNAME_roleAssignments": { - "copy": { - "name": "CNAME_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "CNAME" + "vm", + "vm_nvidiaGpuDriverWindowsExtension" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed CNAME record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed CNAME record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed CNAME record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_MX": { - "copy": { - "name": "privateDnsZone_MX", - "count": "[length(coalesce(parameters('mx'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" - }, - "mxRecords": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2977624679479439942" }, - "name": "Private DNS Zone MX record", - "description": "This module deploys a Private DNS Zone MX record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_azureGuestConfigurationExtension": { + "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.GuestConfiguration" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, + "protectedSettings": { + "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the MX record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "vm", + "vm_hostPoolRegistrationExtension" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_backup": { + "condition": "[not(empty(parameters('backupVaultName')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('backupVaultResourceGroup')]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyId": { + "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + }, + "protectedItemType": { + "value": "Microsoft.Compute/virtualMachines" + }, + "protectionContainerName": { + "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "recoveryVaultName": { + "value": "[parameters('backupVaultName')]" + }, + "sourceResourceId": { + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17448691641471706096" + }, + "name": "Recovery Service Vaults Protection Container Protected Item", + "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "protectionContainerName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + } + }, + "recoveryVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "protectedItemType": { + "type": "string", + "allowedValues": [ + "AzureFileShareProtectedItem", + "AzureVmWorkloadSAPAseDatabase", + "AzureVmWorkloadSAPHanaDatabase", + "AzureVmWorkloadSQLDatabase", + "DPMProtectedItem", + "GenericProtectedItem", + "MabFileFolderProtectedItem", + "Microsoft.ClassicCompute/virtualMachines", + "Microsoft.Compute/virtualMachines", + "Microsoft.Sql/servers/databases" + ], + "metadata": { + "description": "Required. The backup item type." + } + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Required. ID of the backup policy with which this item is backed up." + } + }, + "sourceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource to back up." + } + } + }, + "resources": [ + { + "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", + "apiVersion": "2025-02-01", + "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "protectedItemType": "[parameters('protectedItemType')]", + "policyId": "[parameters('policyId')]", + "sourceResourceId": "[parameters('sourceResourceId')]" + } + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the protected item was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the protected item." + }, + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The Name of the protected item." + }, + "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "MX": { - "type": "Microsoft.Network/privateDnsZones/MX", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "mxRecords": "[parameters('mxRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "MX_roleAssignments": { - "copy": { - "name": "MX_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "MX" + "vm", + "vm_azureGuestConfigurationExtension" ] } }, @@ -17848,65 +14193,123 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed MX record." + "description": "The name of the VM." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed MX record." + "description": "The resource ID of the VM." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed MX record." + "description": "The name of the resource group the VM was created in." }, "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2024-07-01', 'full').location]" + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationOutputType" + }, + "metadata": { + "description": "The list of NIC configurations of the virtual machine." + }, + "copy": { + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", + "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" + } + } } } } }, "dependsOn": [ - "privateDnsZone" + "logAnalyticsWorkspace", + "maintenanceConfiguration", + "virtualNetwork", + "windowsVmDataCollectionRules" ] }, - "privateDnsZone_PTR": { - "copy": { - "name": "privateDnsZone_PTR", - "count": "[length(coalesce(parameters('ptr'), createArray()))]" - }, + "maintenanceConfiguration": { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + "value": "[format('mc-{0}', variables('jumpboxVmName'))]" }, - "metadata": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" }, - "ptrRecords": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + "extensionProperties": { + "value": { + "InGuestPatchMode": "User" + } }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + "maintenanceScope": { + "value": "InGuestPatch" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "maintenanceWindow": { + "value": { + "startDateTime": "2024-06-16 00:00", + "duration": "03:55", + "timeZone": "W. Europe Standard Time", + "recurEvery": "1Day" + } + }, + "visibility": { + "value": "Custom" + }, + "installPatches": { + "value": { + "rebootSetting": "IfRequired", + "windowsParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + }, + "linuxParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + } + } } }, "template": { @@ -17917,303 +14320,49 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "15286275176817336979" + "templateHash": "14895287194406877557" }, - "name": "Private DNS Zone PTR record", - "description": "This module deploys a Private DNS Zone PTR record." + "name": "Maintenance Configurations", + "description": "This module deploys a Maintenance Configuration." }, "definitions": { - "roleAssignmentType": { + "lockType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. Specify the name of lock." } }, - "conditionVersion": { + "kind": { "type": "string", "allowedValues": [ - "2.0" + "CanNotDelete", + "None", + "ReadOnly" ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Specify the type of lock." } }, - "delegatedManagedIdentityResourceId": { + "notes": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the PTR record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "PTR": { - "type": "Microsoft.Network/privateDnsZones/PTR", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ptrRecords": "[parameters('ptrRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "PTR_roleAssignments": { - "copy": { - "name": "PTR_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "PTR" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed PTR record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed PTR record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed PTR record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SOA": { - "copy": { - "name": "privateDnsZone_SOA", - "count": "[length(coalesce(parameters('soa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" - }, - "soaRecord": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4837447718856535826" - }, - "name": "Private DNS Zone SOA record", - "description": "This module deploys a Private DNS Zone SOA record." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -18285,56 +14434,74 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "privateDnsZoneName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + "description": "Required. Maintenance Configuration Name." } }, - "name": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. The name of the SOA record." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "metadata": { + "extensionProperties": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" }, - "description": "Optional. The metadata attached to the record set." + "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." }, - "nullable": true + "defaultValue": {} }, - "soaRecord": { - "type": "object", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "maintenanceScope": { + "type": "string", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" }, - "description": "Optional. A SOA record." + "description": "Optional. Gets or sets maintenanceScope of the configuration." }, - "nullable": true + "defaultValue": "Host" }, - "ttl": { - "type": "int", - "defaultValue": 3600, + "maintenanceWindow": { + "type": "object", "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" + }, + "description": "Optional. Definition of a MaintenanceWindow." + }, + "defaultValue": {} }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "namespace": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Gets or sets namespace of the resource." } }, "roleAssignments": { @@ -18346,6 +14513,36 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" + }, + "description": "Optional. Gets or sets tags of the resource." + }, + "nullable": true + }, + "visibility": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" + }, + "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." + }, + "nullable": true + }, + "installPatches": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" + }, + "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." + }, + "defaultValue": {} } }, "variables": { @@ -18358,11 +14555,10 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -18370,8 +14566,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -18387,31 +14583,44 @@ } } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SOA": { - "type": "Microsoft.Network/privateDnsZones/SOA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "maintenanceConfiguration": { + "type": "Microsoft.Maintenance/maintenanceConfigurations", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "metadata": "[parameters('metadata')]", - "soaRecord": "[parameters('soaRecord')]", - "ttl": "[parameters('ttl')]" + "extensionProperties": "[parameters('extensionProperties')]", + "maintenanceScope": "[parameters('maintenanceScope')]", + "maintenanceWindow": "[parameters('maintenanceWindow')]", + "namespace": "[parameters('namespace')]", + "visibility": "[parameters('visibility')]", + "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" } }, - "SOA_roleAssignments": { + "maintenanceConfiguration_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + }, + "maintenanceConfiguration_roleAssignments": { "copy": { - "name": "SOA_roleAssignments", + "name": "maintenanceConfiguration_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -18422,7 +14631,7 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "SOA" + "maintenanceConfiguration" ] } }, @@ -18430,65 +14639,162 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed SOA record." + "description": "The name of the Maintenance Configuration." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed SOA record." + "description": "The resource ID of the Maintenance Configuration." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed SOA record." + "description": "The name of the resource group the Maintenance Configuration was created in." }, "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the Maintenance Configuration was created in." + }, + "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" } } } - }, - "dependsOn": [ - "privateDnsZone" - ] + } }, - "privateDnsZone_SRV": { - "copy": { - "name": "privateDnsZone_SRV", - "count": "[length(coalesce(parameters('srv'), createArray()))]" - }, + "windowsVmDataCollectionRules": { + "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + "value": "[variables('dataCollectionRulesResourceName')]" }, - "srvRecords": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + "tags": { + "value": "[parameters('tags')]" }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + "location": { + "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "dataCollectionRuleProperties": { + "value": { + "kind": "Windows", + "dataSources": { + "performanceCounters": [ + { + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Processes", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Handle Count", + "\\System\\System Up Time", + "\\System\\Context Switches/sec", + "\\System\\Processor Queue Length", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pages/sec", + "\\Memory\\Page Faults/sec", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors" + ], + "name": "perfCounterDataSource60" + } + ], + "windowsEventLogs": [ + { + "name": "SecurityAuditEvents", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" + ] + } + ] + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", + "name": "[variables('dcrLogAnalyticsDestinationName')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Microsoft-Perf" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Perf" + }, + { + "streams": [ + "Microsoft-Event" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Event" + } + ] + } } }, "template": { @@ -18499,303 +14805,573 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "15028912535488490265" + "templateHash": "2441324888126124697" }, - "name": "Private DNS Zone SRV record", - "description": "This module deploys a Private DNS Zone SRV record." + "name": "Data Collection Rules", + "description": "This module deploys a Data Collection Rule." }, "definitions": { - "roleAssignmentType": { + "dataCollectionRulePropertiesType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Linux": { + "$ref": "#/definitions/linuxDcrPropertiesType" + }, + "Windows": { + "$ref": "#/definitions/windowsDcrPropertiesType" + }, + "All": { + "$ref": "#/definitions/allPlatformsDcrPropertiesType" + }, + "AgentSettings": { + "$ref": "#/definitions/agentSettingsDcrPropertiesType" + }, + "Direct": { + "$ref": "#/definitions/directDcrPropertiesType" + }, + "WorkspaceTransforms": { + "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" + }, + "PlatformTelemetry": { + "$ref": "#/definitions/platformTelemetryDcrPropertiesType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." + } + }, + "linuxDcrPropertiesType": { "type": "object", "properties": { - "name": { + "kind": { "type": "string", - "nullable": true, + "allowedValues": [ + "Linux" + ], "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Required. The kind of the resource." } }, - "roleDefinitionIdOrName": { - "type": "string", + "dataSources": { + "type": "object", "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." } }, - "principalId": { - "type": "string", + "dataFlows": { + "type": "array", "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." } }, - "principalType": { + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." } }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Linux' data collection rule." + } + }, + "windowsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Windows" + ], + "metadata": { + "description": "Required. The kind of the resource." } }, - "condition": { + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." } }, - "conditionVersion": { + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Windows' data collection rule." + } + }, + "allPlatformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { "type": "string", "allowedValues": [ - "2.0" + "All" ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." } }, - "delegatedManagedIdentityResourceId": { + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Description of the data collection rule." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SRV record." + "description": "The type for the properties of the data collection rule of the kind 'All'." } }, - "metadata": { + "agentSettingsDcrPropertiesType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AgentSettings" + ], + "metadata": { + "description": "Required. The kind of the resource." + } }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "srvRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } }, - "description": "Optional. The list of SRV records in the record set." + "agentSettings": { + "$ref": "#/definitions/agentSettingsType", + "metadata": { + "description": "Required. Agent settings used to modify agent behavior on a given host." + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." + "description": "The type for the properties of the 'AgentSettings' data collection rule." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "agentSettingsType": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agentSettingType" + }, + "metadata": { + "description": "Required. All the settings that are applicable to the logs agent (AMA)." + } + } + }, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "The type for the agent settings." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "agentSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "MaxDiskQuotaInMB", + "UseTimeReceivedForForwardedEvents" + ], + "metadata": { + "description": "Required. The name of the agent setting." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the agent setting." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "The type for the (single) agent setting." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + }, + "directDcrPropertiesType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "kind": { + "type": "string", + "allowedValues": [ + "Direct" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Required. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." } } + }, + "metadata": { + "description": "The type for the properties of the 'Direct' data collection rule." } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SRV": { - "type": "Microsoft.Network/privateDnsZones/SRV", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "workspaceTransformsDcrPropertiesType": { + "type": "object", "properties": { - "metadata": "[parameters('metadata')]", - "srvRecords": "[parameters('srvRecords')]", - "ttl": "[parameters('ttl')]" + "kind": { + "type": "string", + "allowedValues": [ + "WorkspaceTransforms" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." } }, - "SRV_roleAssignments": { - "copy": { - "name": "SRV_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "platformTelemetryDcrPropertiesType": { + "type": "object", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "kind": { + "type": "string", + "allowedValues": [ + "PlatformTelemetry" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "dataSources": { + "type": "object", + "properties": { + "platformTelemetry": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + }, + "description": "Required. The list of platform telemetry configurations." + } + } + }, + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "destinations": { + "type": "object", + "properties": { + "logAnalytics": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + }, + "description": "Optional. The list of Log Analytics destinations." + }, + "nullable": true + }, + "storageAccounts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + }, + "description": "Optional. The list of Storage Account destinations." + }, + "nullable": true + }, + "eventHubs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + }, + "description": "Optional. The list of Event Hub destinations." + }, + "nullable": true + } + }, + "metadata": { + "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + } }, - "dependsOn": [ - "SRV" - ] - } - }, - "outputs": { - "name": { - "type": "string", "metadata": { - "description": "The name of the deployed SRV record." - }, - "value": "[parameters('name')]" + "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." + } }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SRV record." + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SRV record." + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_TXT": { - "copy": { - "name": "privateDnsZone_TXT", - "count": "[length(coalesce(parameters('txt'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" - }, - "txtRecords": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7641583415110009849" + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "name": "Private DNS Zone TXT record", - "description": "This module deploys a Private DNS Zone TXT record." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -18867,56 +15443,50 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "privateDnsZoneName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + "description": "Required. The name of the data collection rule. The name is case insensitive." } }, - "name": { - "type": "string", + "dataCollectionRuleProperties": { + "$ref": "#/definitions/dataCollectionRulePropertiesType", "metadata": { - "description": "Required. The name of the TXT record." + "description": "Required. The kind of data collection rule." } }, - "metadata": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "ttl": { - "type": "int", - "defaultValue": 3600, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." + "description": "Optional. Location for all Resources." } }, - "txtRecords": { - "type": "array", + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" - }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true + "description": "Optional. The lock settings of the service." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The managed identity definition for this resource." } }, "roleAssignments": { @@ -18928,6 +15498,16 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true } }, "variables": { @@ -18938,22 +15518,24 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", + "enableReferencedModulesTelemetry": false }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -18969,246 +15551,412 @@ } } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" + "dataCollectionRule": { + "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('dataCollectionRuleProperties').kind]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" }, - "TXT": { - "type": "Microsoft.Network/privateDnsZones/TXT", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]", - "txtRecords": "[parameters('txtRecords')]" - } + "dataCollectionRuleAll": { + "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" }, - "TXT_roleAssignments": { - "copy": { - "name": "TXT_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "dataCollectionRule_conditionalScopeLock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", + "lock": { + "value": "[parameters('lock')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2876136109547890997" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "dataCollectionRuleName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + } + } + }, + "resources": { + "dataCollectionRule": { + "existing": true, + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dataCollectionRuleName')]" + }, + "dataCollectionRule_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + } + } + } }, "dependsOn": [ - "TXT" + "dataCollectionRule", + "dataCollectionRuleAll" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed TXT record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed TXT record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed TXT record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "resolutionPolicy": { - "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7392770862892927923" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link." - }, - "parameters": { - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" - }, - "description": "Optional. Tags of the resource." + "dataCollectionRule_roleAssignments": { + "copy": { + "name": "dataCollectionRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "nullable": true - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - }, - "resolutionPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", + "name": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14634305923902101494" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource." + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - }, - "resolutionPolicy": "[parameters('resolutionPolicy')]" - } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed virtual network link." + "description": "The name of the dataCollectionRule." }, - "value": "[parameters('name')]" + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed virtual network link." + "description": "The resource ID of the dataCollectionRule." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed virtual network link." + "description": "The name of the resource group the dataCollectionRule was created in." }, "value": "[resourceGroup().name]" }, @@ -19217,183 +15965,54 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" + }, + "endpoints": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", + "output": true + }, + "description": "The endpoints of the dataCollectionRule, if created." + }, + "nullable": true, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" + }, + "immutableId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The ImmutableId of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" } } } }, "dependsOn": [ - "privateDnsZone" + "logAnalyticsWorkspace" ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "logAnalyticsWorkspace": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('logAnalyticsWorkspaceResourceName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "existingLogAnalyticsWorkspaceId": { - "value": "[parameters('existingLogAnalyticsWorkspaceId')]" - }, - "enablePrivateNetworking": { - "value": "[parameters('enablePrivateNetworking')]" - }, - "enableRedundancy": { - "value": "[parameters('enableRedundancy')]" - }, - "replicaLocation": { - "value": "[variables('replicaLocation')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "15098611015028470375" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of Log analytics Workspace" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location for the Resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" - }, - "description": "Optional. Tags to be applied to the resources." + "avmPrivateDnsZones": { + "copy": { + "name": "avmPrivateDnsZones", + "count": "[length(variables('privateDnsZones'))]", + "mode": "serial", + "batchSize": 5 }, - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - } - }, - "existingLogAnalyticsWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Existing Log Analytics Workspace Resource ID" - } - }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable Private Networking for Log Analytics Workspace." - } - }, - "enableRedundancy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable Redundancy for Log Analytics Workspace." - } - }, - "replicaLocation": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The replica location for Log Analytics Workspace, if redundancy is enabled." - } - } - }, - "variables": { - "useExistingWorkspace": "[not(empty(parameters('existingLogAnalyticsWorkspaceId')))]", - "existingLawSubscription": "[if(variables('useExistingWorkspace'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[2], '')]", - "existingLawResourceGroup": "[if(variables('useExistingWorkspace'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[4], '')]", - "existingLawName": "[if(variables('useExistingWorkspace'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[8], '')]" - }, - "resources": { - "existingLogAnalyticsWorkspace": { - "condition": "[variables('useExistingWorkspace')]", - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "subscriptionId": "[variables('existingLawSubscription')]", - "resourceGroup": "[variables('existingLawResourceGroup')]", - "name": "[variables('existingLawName')]" - }, - "logAnalyticsWorkspace": { - "condition": "[not(variables('useExistingWorkspace'))]", + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", + "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -19401,40 +16020,21 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('name')]" + "value": "[variables('privateDnsZones')[copyIndex()]]" }, "tags": { "value": "[parameters('tags')]" }, - "location": { - "value": "[parameters('location')]" - }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "skuName": { - "value": "PerGB2018" - }, - "dataRetention": { - "value": 365 - }, - "features": { - "value": { - "enableLogAccessUsingOnlyResourcePermissions": true - } - }, - "diagnosticSettings": { + "virtualNetworkLinks": { "value": [ { - "useThisWorkspace": true + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" } ] - }, - "dailyQuotaGb": "[if(parameters('enableRedundancy'), createObject('value', '150'), createObject('value', null()))]", - "replication": "[if(parameters('enableRedundancy'), createObject('value', createObject('enabled', true(), 'location', parameters('replicaLocation'))), createObject('value', null()))]", - "publicNetworkAccessForIngestion": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "publicNetworkAccessForQuery": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "dataSources": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('tags', parameters('tags'), 'eventLogName', 'Application', 'eventTypes', createArray(createObject('eventType', 'Error'), createObject('eventType', 'Warning'), createObject('eventType', 'Information')), 'kind', 'WindowsEvent', 'name', 'applicationEvent'), createObject('counterName', '% Processor Time', 'instanceName', '*', 'intervalSeconds', 60, 'kind', 'WindowsPerformanceCounter', 'name', 'windowsPerfCounter1', 'objectName', 'Processor'), createObject('kind', 'IISLogs', 'name', 'sampleIISLog1', 'state', 'OnPremiseEnabled'))), createObject('value', null()))]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -19443,513 +16043,193 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14099489006827800075" + "version": "0.41.2.15936", + "templateHash": "18337341331267624582" }, - "name": "Log Analytics Workspaces", - "description": "This module deploys a Log Analytics Workspace." + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone." }, "definitions": { - "diagnosticSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "useThisWorkspace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "gallerySolutionType": { + "aType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the gallery solutions to be created in the log analytics workspace." - } - }, - "storageInsightsConfigType": { - "type": "object", - "properties": { - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the storage account to be linked." + "description": "Required. The name of the record." } }, - "containers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "items": { - "type": "string" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." }, - "nullable": true, - "metadata": { - "description": "Optional. List of tables to be read by the workspace." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the storage insights configuration." - } - }, - "linkedServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." - } + "nullable": true }, - "writeAccessResourceId": { - "type": "string", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked service." - } - }, - "linkedStorageAccountType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the link." + "description": "Optional. The TTL of the record." } }, - "storageAccountIds": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked storage account." - } - }, - "savedSearchType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "etag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. The category of the saved search. This helps the user to find a saved search faster." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "functionAlias": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The function alias if query serves as a function." - } - }, - "functionParameters": { - "type": "string", "nullable": true, "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. The query expression for the saved search." + "description": "Optional. Array of role assignments to create." } }, - "tags": { + "aRecords": { "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The tags attached to the saved search." - } - }, - "version": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The version number of the query language. The current version is 2 and is the default." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the saved search." - } - }, - "dataExportType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data export." - } - }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, - "metadata": { - "description": "Optional. The destination of the data export." - } - }, - "enable": { - "type": "bool", - "nullable": true, "metadata": { - "description": "Optional. Enable or disable the data export." - } - }, - "tableNames": { - "type": "array", - "items": { - "type": "string" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." }, - "metadata": { - "description": "Required. The list of table names to export." - } + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Properties of the data export." + "description": "The type for the A record." } }, - "dataSourceType": { + "aaaaType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "metadata": { - "description": "Required. The kind of data source." - } - }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the event log to configure when kind is WindowsEvent." - } - }, - "eventTypes": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "intervalSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + "description": "Required. The name of the record." } }, - "syslogName": { - "type": "string", + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." + "description": "Optional. The TTL of the record." } }, - "syslogSeverities": { + "roleAssignments": { "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." + "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", + "aaaaRecords": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The list of AAAA records in the record set." }, "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Properties of the data source." + "description": "The type for the AAAA record." } }, - "tableType": { + "cnameType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the table." + "description": "Required. The name of the record." } }, - "plan": { - "type": "string", - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. The plan for the table." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The restored logs for the table." + "description": "Optional. The TTL of the record." } }, - "schema": { - "$ref": "#/definitions/schemaType", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The schema for the table." + "description": "Optional. Array of role assignments to create." } }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. The CNAME record in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the CNAME record." + } + }, + "mxType": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "description": "Optional. The search results for the table." + "description": "Required. The name of the record." } }, - "retentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "totalRetentionInDays": { + "ttl": { "type": "int", "nullable": true, - "minValue": 4, - "maxValue": 2555, "metadata": { - "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + "description": "Optional. The TTL of the record." } }, "roleAssignments": { @@ -19959,262 +16239,326 @@ }, "nullable": true, "metadata": { - "description": "Optional. The role assignments for the table." + "description": "Optional. Array of role assignments to create." } + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Properties of the custom table." + "description": "The type for the MX record." } }, - "workspaceFeaturesType": { + "ptrType": { "type": "object", "properties": { - "disableLocalAuth": { - "type": "bool", - "nullable": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. Disable Non-EntraID based Auth. Default is true." + "description": "Required. The name of the record." } }, - "enableDataExport": { - "type": "bool", - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. Flag that indicate if data should be exported." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "enableLogAccessUsingOnlyResourcePermissions": { - "type": "bool", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Enable log access using only resource permissions. Default is false." + "description": "Optional. The TTL of the record." } }, - "immediatePurgeDataOn30Days": { - "type": "bool", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Flag that describes if we want to remove the data after 30 days." + "description": "Optional. Array of role assignments to create." } + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Features of the workspace." + "description": "The type for the PTR record." } }, - "workspaceReplicationType": { + "soaType": { "type": "object", "properties": { - "enabled": { - "type": "bool", + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." + "description": "Optional. The TTL of the record." } }, - "location": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." + "description": "Optional. Array of role assignments to create." } + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. The SOA record in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Replication properties of the workspace." + "description": "The type for the SOA record." } }, - "_1.columnType": { + "srvType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The column name." + "description": "Required. The name of the record." } }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], + "metadata": { + "type": "object", "metadata": { - "description": "Required. The column type." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The column data type logical hint." + "description": "Optional. The TTL of the record." } }, - "description": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The column description." + "description": "Optional. Array of role assignments to create." } }, - "displayName": { - "type": "string", - "nullable": true, + "srvRecords": { + "type": "array", "metadata": { - "description": "Optional. Column display name." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true } }, "metadata": { - "description": "The parameters of the table column.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } + "__bicep_export!": true, + "description": "The type for the SRV record." } }, - "destinationType": { + "txtType": { "type": "object", "properties": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "Required. The destination resource ID." + "description": "Required. The name of the record." } }, - "metaData": { + "metadata": { "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The destination metadata." + "description": "Optional. Array of role assignments to create." } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true } }, "metadata": { - "description": "The data export destination properties.", - "__bicep_imported_from!": { - "sourceTemplate": "data-export/main.bicep" - } + "__bicep_export!": true, + "description": "The type for the TXT record." } }, - "lockType": { + "virtualNetworkLinkType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, + "minLength": 1, + "maxLength": 80, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The resource name." } }, - "kind": { + "virtualNetworkResourceId": { "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Required. The resource ID of the virtual network to link." } }, - "notes": { + "location": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. The Azure Region where the resource lives." } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { + }, + "registrationEnabled": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." } }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Resource tags." }, + "nullable": true + }, + "resolutionPolicy": { + "type": "string", + "allowedValues": [ + "Default", + "NxDomainRedirect" + ], "nullable": true, "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "description": "Optional. The resolution type of the private-dns-zone fallback machanism." } } }, "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "__bicep_export!": true, + "description": "The type for the virtual network link." } }, - "restoredLogsType": { + "lockType": { "type": "object", "properties": { - "sourceTable": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The table to restore data from." + "description": "Optional. Specify the name of lock." } }, - "startRestoreTime": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." + "description": "Optional. Specify the type of lock." } }, - "endRestoreTime": { + "notes": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "The parameters of the restore operation that initiated the table.", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } }, @@ -20289,122 +16633,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "description": "The table schema.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the search job that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } @@ -20413,219 +16642,104 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the Log Analytics workspace." + "description": "Required. Private DNS zone name." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "allowedValues": [ - "CapacityReservation", - "Free", - "LACluster", - "PerGB2018", - "PerNode", - "Premium", - "Standalone", - "Standard" - ], - "metadata": { - "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." - } - }, - "skuCapacityReservationLevel": { - "type": "int", - "defaultValue": 100, - "minValue": 100, - "maxValue": 5000, - "metadata": { - "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." - } - }, - "storageInsightsConfigs": { + "a": { "type": "array", "items": { - "$ref": "#/definitions/storageInsightsConfigType" + "$ref": "#/definitions/aType" }, "nullable": true, "metadata": { - "description": "Optional. List of storage accounts to be read by the workspace." + "description": "Optional. Array of A records." } }, - "linkedServices": { + "aaaa": { "type": "array", "items": { - "$ref": "#/definitions/linkedServiceType" + "$ref": "#/definitions/aaaaType" }, "nullable": true, "metadata": { - "description": "Optional. List of services to be linked." + "description": "Optional. Array of AAAA records." } }, - "linkedStorageAccounts": { + "cname": { "type": "array", "items": { - "$ref": "#/definitions/linkedStorageAccountType" + "$ref": "#/definitions/cnameType" }, "nullable": true, "metadata": { - "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + "description": "Optional. Array of CNAME records." } }, - "savedSearches": { + "mx": { "type": "array", "items": { - "$ref": "#/definitions/savedSearchType" + "$ref": "#/definitions/mxType" }, "nullable": true, "metadata": { - "description": "Optional. Kusto Query Language searches to save." + "description": "Optional. Array of MX records." } }, - "dataExports": { + "ptr": { "type": "array", "items": { - "$ref": "#/definitions/dataExportType" + "$ref": "#/definitions/ptrType" }, "nullable": true, "metadata": { - "description": "Optional. LAW data export instances to be deployed." + "description": "Optional. Array of PTR records." } }, - "dataSources": { + "soa": { "type": "array", "items": { - "$ref": "#/definitions/dataSourceType" + "$ref": "#/definitions/soaType" }, "nullable": true, "metadata": { - "description": "Optional. LAW data sources to configure." + "description": "Optional. Array of SOA records." } }, - "tables": { + "srv": { "type": "array", "items": { - "$ref": "#/definitions/tableType" + "$ref": "#/definitions/srvType" }, "nullable": true, "metadata": { - "description": "Optional. LAW custom tables to be deployed." + "description": "Optional. Array of SRV records." } }, - "gallerySolutions": { + "txt": { "type": "array", "items": { - "$ref": "#/definitions/gallerySolutionType" + "$ref": "#/definitions/txtType" }, "nullable": true, "metadata": { - "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." - } - }, - "onboardWorkspaceToSentinel": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." - } - }, - "dataRetention": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 730, - "metadata": { - "description": "Optional. Number of days data will be retained for." - } - }, - "dailyQuotaGb": { - "type": "string", - "defaultValue": "-1", - "metadata": { - "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." - } - }, - "defaultDataCollectionRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics query." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." - } - }, - "features": { - "$ref": "#/definitions/workspaceFeaturesType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace features." - } - }, - "replication": { - "$ref": "#/definitions/workspaceReplicationType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace replication properties." + "description": "Optional. Array of TXT records." } }, - "diagnosticSettings": { + "virtualNetworkLinks": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingType" + "$ref": "#/definitions/virtualNetworkLinkType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "forceCmkForQuery": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "location": { + "type": "string", + "defaultValue": "global", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. The location of the PrivateDNSZone. Should be global." } }, "roleAssignments": { @@ -20640,13 +16754,17 @@ }, "tags": { "type": "object", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" - }, "description": "Optional. Tags of the resource." - }, - "nullable": true + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } }, "enableTelemetry": { "type": "bool", @@ -20664,149 +16782,67 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", - "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "features": { - "searchVersion": 1, - "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", - "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", - "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", - "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" - }, - "retentionInDays": "[parameters('dataRetention')]", - "workspaceCapping": { - "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" - }, - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "forceCmkForQuery": "[parameters('forceCmkForQuery')]", - "replication": "[parameters('replication')]", - "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" - }, - "identity": "[variables('identity')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" }, - "logAnalyticsWorkspace_diagnosticSettings": { - "copy": { - "name": "logAnalyticsWorkspace_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + } + } }, - "logAnalyticsWorkspace_sentinelOnboarding": { - "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", - "type": "Microsoft.SecurityInsights/onboardingStates", - "apiVersion": "2025-09-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "default", - "properties": {}, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" }, - "logAnalyticsWorkspace_lock": { + "privateDnsZone_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_roleAssignments": { + "privateDnsZone_roleAssignments": { "copy": { - "name": "logAnalyticsWorkspace_roleAssignments", + "name": "privateDnsZone_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -20817,34 +16853,43 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_storageInsightConfigs": { + "privateDnsZone_A": { "copy": { - "name": "logAnalyticsWorkspace_storageInsightConfigs", - "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" + "name": "privateDnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, - "containers": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" + "name": { + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" }, - "tables": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" + "metadata": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -20854,145 +16899,288 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "140290971998938797" + "version": "0.41.2.15936", + "templateHash": "7372385900111002873" }, - "name": "Log Analytics Workspace Storage Insight Configs", - "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } }, "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, "name": { "type": "string", - "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", "metadata": { - "description": "Optional. The name of the storage insights config." + "description": "Required. The name of the A record." } }, - "storageAccountResourceId": { - "type": "string", + "aRecords": { + "type": "array", "metadata": { - "description": "Required. The Azure Resource Manager ID of the storage account resource." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true }, - "containers": { - "type": "array", - "items": { - "type": "string" + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." }, - "nullable": true, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "tables": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The names of the Azure tables that the workspace should read." + "description": "Optional. Array of role assignments to create." } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "workspace": { + "privateDnsZone": { "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "storageinsightconfig": { - "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "containers": "[parameters('containers')]", - "tables": "[parameters('tables')]", - "storageAccount": { - "id": "[parameters('storageAccountResourceId')]", - "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - } + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] } }, "outputs": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed storage insights configuration." + "description": "The name of the deployed A record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[parameters('name')]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group where the storage insight configuration is deployed." + "description": "The resource ID of the deployed A record." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the storage insights configuration." + "description": "The resource group of the deployed A record." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_linkedServices": { + "privateDnsZone_AAAA": { "copy": { - "name": "logAnalyticsWorkspace_linkedServices", - "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + "name": "privateDnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" }, - "resourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" }, - "writeAccessResourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21002,199 +17190,244 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14482465616812596213" + "version": "0.41.2.15936", + "templateHash": "14405855828972373002" }, - "name": "Log Analytics Workspace Linked Services", - "description": "This module deploys a Log Analytics Workspace Linked Service." + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Required. Name of the link." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "resourceId": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "writeAccessResourceId": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + "description": "Required. The name of the AAAA record." } }, - "tags": { - "type": "object", + "aaaaRecords": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The list of AAAA records in the record set." }, "nullable": true - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "linkedService": { - "type": "Microsoft.OperationalInsights/workspaces/linkedServices", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resourceId": "[parameters('resourceId')]", - "writeAccessResourceId": "[parameters('writeAccessResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed linked service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed linked service." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" }, - "resourceGroupName": { - "type": "string", + "metadata": { + "type": "object", "metadata": { - "description": "The resource group where the linked service is deployed." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_linkedStorageAccounts": { - "copy": { - "name": "logAnalyticsWorkspace_linkedStorageAccounts", - "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" - }, - "storageAccountIds": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14864721709229272590" + "nullable": true }, - "name": "Log Analytics Workspace Linked Storage Accounts", - "description": "This module deploys a Log Analytics Workspace Linked Storage Account." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "name": { - "type": "string", - "allowedValues": [ - "Query", - "Alerts", - "CustomLogs", - "AzureWatson" - ], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. Name of the link." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "storageAccountIds": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, + "nullable": true, "metadata": { - "description": "Required. Linked storage accounts resources Ids." + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "linkedStorageAccount": { - "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "storageAccountIds": "[parameters('storageAccountIds')]" + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed linked storage account." + "description": "The name of the deployed AAAA record." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed linked storage account." + "description": "The resource ID of the deployed AAAA record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group where the linked storage account is deployed." + "description": "The resource group of the deployed AAAA record." }, "value": "[resourceGroup().name]" } @@ -21202,52 +17435,43 @@ } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_savedSearches": { + "privateDnsZone_CNAME": { "copy": { - "name": "logAnalyticsWorkspace_savedSearches", - "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + "name": "privateDnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" - }, - "etag": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" }, - "displayName": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" }, - "category": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" - }, - "query": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" - }, - "functionAlias": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" }, - "functionParameters": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "tags": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" }, - "version": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21257,163 +17481,288 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17904092372918022238" + "version": "0.41.2.15936", + "templateHash": "13818627461335065928" }, - "name": "Log Analytics Workspace Saved Searches", - "description": "This module deploys a Log Analytics Workspace Saved Search." + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Required. Name of the saved search." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "displayName": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Display name for the search." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "category": { + "name": { "type": "string", "metadata": { - "description": "Required. Query category." + "description": "Required. The name of the CNAME record." } }, - "query": { - "type": "string", + "cnameRecord": { + "type": "object", "metadata": { - "description": "Required. Kusto Query to be stored." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. A CNAME record." + }, + "nullable": true }, - "tags": { - "type": "array", + "metadata": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The metadata attached to the record set." }, "nullable": true }, - "functionAlias": { - "type": "string", - "defaultValue": "", + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. The function alias if query serves as a function." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "functionParameters": { - "type": "string", - "defaultValue": "", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "version": { - "type": "int", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The version number of the query language." + "description": "Optional. Array of role assignments to create." } - }, - "etag": { - "type": "string", - "defaultValue": "*", - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "savedSearch": { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "etag": "[parameters('etag')]", - "tags": "[coalesce(parameters('tags'), createArray())]", - "displayName": "[parameters('displayName')]", - "category": "[parameters('category')]", - "query": "[parameters('query')]", - "functionAlias": "[parameters('functionAlias')]", - "functionParameters": "[parameters('functionParameters')]", - "version": "[parameters('version')]" + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] } }, "outputs": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed saved search." + "description": "The name of the deployed CNAME record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[parameters('name')]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group where the saved search is deployed." + "description": "The resource ID of the deployed CNAME record." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the deployed saved search." + "description": "The resource group of the deployed CNAME record." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace", - "logAnalyticsWorkspace_linkedStorageAccounts" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_dataExports": { + "privateDnsZone_MX": { "copy": { - "name": "logAnalyticsWorkspace_dataExports", - "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + "name": "privateDnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "workspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" }, - "destination": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" }, - "enable": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "tableNames": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21423,122 +17772,244 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17943947755417749524" + "version": "0.41.2.15936", + "templateHash": "2977624679479439942" }, - "name": "Log Analytics Workspace Data Exports", - "description": "This module deploys a Log Analytics Workspace Data Export." + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." }, "definitions": { - "destinationType": { + "roleAssignmentType": { "type": "object", "properties": { - "resourceId": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The destination resource ID." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The destination metadata." + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The data export destination properties." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } } }, "parameters": { - "name": { + "privateDnsZoneName": { "type": "string", - "minLength": 4, - "maxLength": 63, "metadata": { - "description": "Required. The data export rule name." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "workspaceName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + "description": "Required. The name of the MX record." } }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. Destination properties." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "enable": { + "enableTelemetry": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { - "description": "Optional. Active when enabled." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "tableNames": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, + "nullable": true, "metadata": { - "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "dataExport": { - "type": "Microsoft.OperationalInsights/workspaces/dataExports", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "destination": "[parameters('destination')]", - "enable": "[parameters('enable')]", - "tableNames": "[parameters('tableNames')]" + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the data export." + "description": "The name of the deployed MX record." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the data export." + "description": "The resource ID of the deployed MX record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the data export was created in." + "description": "The resource group of the deployed MX record." }, "value": "[resourceGroup().name]" } @@ -21546,67 +18017,43 @@ } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_dataSources": { + "privateDnsZone_PTR": { "copy": { - "name": "logAnalyticsWorkspace_dataSources", - "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + "name": "privateDnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" - }, - "kind": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" - }, - "linkedResourceId": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" }, - "eventLogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" - }, - "eventTypes": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" - }, - "objectName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" - }, - "instanceName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" - }, - "intervalSeconds": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" - }, - "counterName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" - }, - "state": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" }, - "syslogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" }, - "syslogSeverities": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "performanceCounters": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" }, - "tags": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21616,227 +18063,288 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "15360290236166491819" + "version": "0.41.2.15936", + "templateHash": "15286275176817336979" }, - "name": "Log Analytics Workspace Datasources", - "description": "This module deploys a Log Analytics Workspace Data Source." + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "name": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Name of the data source." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "kind": { + "name": { "type": "string", - "defaultValue": "AzureActivityLog", - "allowedValues": [ - "AzureActivityLog", - "WindowsEvent", - "WindowsPerformanceCounter", - "IISLogs", - "LinuxSyslog", - "LinuxSyslogCollection", - "LinuxPerformanceObject", - "LinuxPerformanceCollection" - ], "metadata": { - "description": "Optional. The kind of the data source." + "description": "Required. The name of the PTR record." } }, - "tags": { + "metadata": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The metadata attached to the record set." }, "nullable": true }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the resource to be linked." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Windows event log name to configure when kind is WindowsEvent." - } - }, - "eventTypes": { + "ptrRecords": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Windows event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "defaultValue": "*", "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true }, - "intervalSeconds": { + "ttl": { "type": "int", - "defaultValue": 60, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, + "defaultValue": 3600, "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "syslogName": { - "type": "string", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "syslogSeverities": { + "roleAssignments": { "type": "array", - "defaultValue": [], + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "dataSource": { - "type": "Microsoft.OperationalInsights/workspaces/dataSources", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "kind": "[parameters('kind')]", - "tags": "[parameters('tags')]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", - "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", - "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", - "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", - "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", - "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", - "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", - "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", - "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", - "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", - "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] } }, "outputs": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed data source." + "description": "The name of the deployed PTR record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[parameters('name')]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group where the data source is deployed." + "description": "The resource ID of the deployed PTR record." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the deployed data source." + "description": "The resource group of the deployed PTR record." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_tables": { + "privateDnsZone_SOA": { "copy": { - "name": "logAnalyticsWorkspace_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" + "name": "privateDnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "workspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "plan": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" - }, - "schema": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" }, - "retentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" - }, - "totalRetentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" }, - "restoredLogs": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" }, - "searchResults": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21846,182 +18354,304 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "18383178824663161801" + "version": "0.41.2.15936", + "templateHash": "4837447718856535826" }, - "name": "Log Analytics Workspace Tables", - "description": "This module deploys a Log Analytics Workspace Table." + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." }, "definitions": { - "restoredLogsType": { + "roleAssignmentType": { "type": "object", "properties": { - "sourceTable": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The table to restore data from." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "startRestoreTime": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the restore operation that initiated the table." - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { + "principalId": { "type": "string", "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "description": { + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The table description." + "description": "Optional. The principal type of the assigned principal ID." } }, - "displayName": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The table schema." - } - }, - "columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." + "description": "Optional. The description of the role assignment." } }, - "type": { + "condition": { "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], + "nullable": true, "metadata": { - "description": "Required. The column type." + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "dataTypeHint": { + "conditionVersion": { "type": "string", "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" + "2.0" ], "nullable": true, "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." + "description": "Optional. Version of the condition." } }, - "displayName": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Column display name." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The parameters of the table column." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "searchResultsType": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." + "description": "Optional. A SOA record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The parameters of the search job that initiated the table." - } + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SRV": { + "copy": { + "name": "privateDnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15028912535488490265" }, + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -22099,66 +18729,50 @@ } }, "parameters": { - "name": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. The name of the table." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "workspaceName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + "description": "Required. The name of the SRV record." } }, - "plan": { - "type": "string", - "defaultValue": "Analytics", - "allowedValues": [ - "Basic", - "Analytics" - ], + "metadata": { + "type": "object", "metadata": { - "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, + "srvRecords": { + "type": "array", "metadata": { - "description": "Optional. Restore parameters." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true }, - "retentionInDays": { + "ttl": { "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, - "metadata": { - "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. Table's schema." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, + "defaultValue": 3600, "metadata": { - "description": "Optional. Parameters of the search job that initiated this table." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "totalRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 2555, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + "description": "Optional. Enable/Disable usage telemetry for module." } }, "roleAssignments": { @@ -22182,10 +18796,8 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", @@ -22193,34 +18805,51 @@ } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "table": { - "type": "Microsoft.OperationalInsights/workspaces/tables", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "plan": "[parameters('plan')]", - "restoredLogs": "[parameters('restoredLogs')]", - "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", - "schema": "[parameters('schema')]", - "searchResults": "[parameters('searchResults')]", - "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" } }, - "table_roleAssignments": { + "SRV_roleAssignments": { "copy": { - "name": "table_roleAssignments", + "name": "SRV_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -22231,7 +18860,7 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "table" + "SRV" ] } }, @@ -22239,21 +18868,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the table." + "description": "The name of the deployed SRV record." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the table." + "description": "The resource ID of the deployed SRV record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the table was created in." + "description": "The resource group of the deployed SRV record." }, "value": "[resourceGroup().name]" } @@ -22261,35 +18890,40 @@ } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_solutions": { + "privateDnsZone_TXT": { "copy": { - "name": "logAnalyticsWorkspace_solutions", - "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + "name": "privateDnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" }, - "condition": "[not(empty(parameters('gallerySolutions')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" }, - "location": { - "value": "[parameters('location')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" }, - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" }, - "plan": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -22302,75 +18936,163 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "10255889523646649592" + "version": "0.41.2.15936", + "templateHash": "7641583415110009849" }, - "name": "Operations Management Solutions", - "description": "This module deploys an Operations Management Solution.", - "owner": "Azure/module-maintainers" + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." }, "definitions": { - "solutionPlanType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "product": { + "conditionVersion": { "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + "description": "Optional. Version of the condition." } }, - "publisher": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } } }, "parameters": { - "name": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "plan": { - "$ref": "#/definitions/solutionPlanType", + "name": { + "type": "string", "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + "description": "Required. The name of the TXT record." } }, - "logAnalyticsWorkspaceName": { - "type": "string", + "metadata": { + "type": "object", "metadata": { - "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { @@ -22378,7 +19100,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -22389,992 +19111,321 @@ "telemetry": { "type": "String", "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2021-06-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "solution": { - "type": "Microsoft.OperationsManagement/solutions", - "apiVersion": "2015-11-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" - }, - "plan": { - "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", - "promotionCode": "", - "product": "[parameters('plan').product]", - "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed solution." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed solution." - }, - "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the solution is deployed." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('solution', '2015-11-01-preview', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed log analytics workspace." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed log analytics workspace." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed log analytics workspace." - }, - "value": "[parameters('name')]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "The ID associated with the workspace." - }, - "value": "[reference('logAnalyticsWorkspace').customerId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" - }, - "primarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The primary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" - }, - "secondarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The secondary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" - } - } - } - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingLawSubscription'), variables('existingLawResourceGroup')), 'Microsoft.OperationalInsights/workspaces', variables('existingLawName')), reference('logAnalyticsWorkspace').outputs.resourceId.value)]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), reference('existingLogAnalyticsWorkspace').customerId, reference('logAnalyticsWorkspace').outputs.logAnalyticsWorkspaceId.value)]" - }, - "primarySharedKey": { - "type": "securestring", - "value": "[if(variables('useExistingWorkspace'), if(variables('useExistingWorkspace'), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingLawSubscription'), variables('existingLawResourceGroup')), 'Microsoft.OperationalInsights/workspaces', variables('existingLawName')), '2020-08-01'), listOutputsWithSecureValues('logAnalyticsWorkspace', '2025-04-01').primarySharedKey).primarySharedKey, listOutputsWithSecureValues('logAnalyticsWorkspace', '2025-04-01').primarySharedKey)]" - }, - "location": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), reference('existingLogAnalyticsWorkspace', '2025-07-01', 'full').location, reference('logAnalyticsWorkspace').outputs.location.value)]" - }, - "name": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), variables('existingLawName'), reference('logAnalyticsWorkspace').outputs.name.value)]" - } - } - } - } - }, - "applicationInsights": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appi-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "retentionInDays": { - "value": 365 - }, - "kind": { - "value": "web" - }, - "disableIpMasking": { - "value": false - }, - "flowType": { - "value": "Bluefield" - }, - "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17358780145253914698" - }, - "name": "Application Insights", - "description": "This component deploys an Application Insights instance." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application Insights." - } - }, - "applicationType": { - "type": "string", - "defaultValue": "web", - "allowedValues": [ - "web", - "other" - ], - "metadata": { - "description": "Optional. Application type." - } - }, - "workspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." - } - }, - "disableIpMasking": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable IP masking. Default value is set to true." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." - } - }, - "forceCustomerStorageForProfiler": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Force users to create their own storage account for profiler and debugger." - } - }, - "linkedStorageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Linked storage account resource ID." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": 365, - "allowedValues": [ - 30, - 60, - 90, - 120, - 180, - 270, - 365, - 550, - 730 - ], - "metadata": { - "description": "Optional. Retention period in days." - } - }, - "samplingPercentage": { - "type": "int", - "defaultValue": 100, - "minValue": 0, - "maxValue": 100, - "metadata": { - "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." - } - }, - "flowType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." - } - }, - "requestSource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." - } - }, - "kind": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." - } - }, - "immediatePurgeDataOn30Days": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Purge data immediately after 30 days." - } - }, - "ingestionMode": { - "type": "string", - "nullable": true, - "allowedValues": [ - "ApplicationInsights", - "ApplicationInsightsWithDiagnosticSettings", - "LogAnalytics" - ], - "metadata": { - "description": "Optional. Indicates the flow of the ingestion." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/components@2020-02-02#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", - "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", - "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "appInsights": { - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "Application_Type": "[parameters('applicationType')]", - "DisableIpMasking": "[parameters('disableIpMasking')]", - "DisableLocalAuth": "[parameters('disableLocalAuth')]", - "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", - "WorkspaceResourceId": "[parameters('workspaceResourceId')]", - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "RetentionInDays": "[parameters('retentionInDays')]", - "SamplingPercentage": "[parameters('samplingPercentage')]", - "Flow_Type": "[parameters('flowType')]", - "Request_Source": "[parameters('requestSource')]", - "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", - "IngestionMode": "[parameters('ingestionMode')]" - } - }, - "appInsights_roleAssignments": { - "copy": { - "name": "appInsights_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_diagnosticSettings": { - "copy": { - "name": "appInsights_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "linkedStorageAccount": { - "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appInsightsName": { - "value": "[parameters('name')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5059808225314360251" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] }, - "name": "Application Insights Linked Storage Account", - "description": "This component deploys an Application Insights Linked Storage Account." + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7392770862892927923" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } }, - "parameters": { - "appInsightsName": { + "outputs": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." - } + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Linked storage account resource ID." - } - } - }, - "resources": [ - { - "type": "microsoft.insights/components/linkedStorageAccounts", - "apiVersion": "2020-03-01-preview", - "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", - "properties": { - "linkedStorageAccount": "[parameters('storageAccountResourceId')]" - } - } - ], - "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the Linked Storage Account." + "description": "The name of the private DNS zone." }, - "value": "ServiceProfiler" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Linked Storage Account." + "description": "The resource ID of the private DNS zone." }, - "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The resource group the agent pool was deployed into." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" } } } }, "dependsOn": [ - "appInsights" + "virtualNetwork" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the application insights component." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application insights component." - }, - "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the application insights component was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "applicationId": { - "type": "string", - "metadata": { - "description": "The application ID of the application insights component." - }, - "value": "[reference('appInsights').AppId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('appInsights', '2020-02-02', 'full').location]" - }, - "instrumentationKey": { - "type": "string", - "metadata": { - "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." - }, - "value": "[reference('appInsights').InstrumentationKey]" - }, - "connectionString": { - "type": "string", - "metadata": { - "description": "Application Insights Connection String." - }, - "value": "[reference('appInsights').ConnectionString]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmManagedIdentity": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('id-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "18123481228095028530" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the managed identity." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Required. The location of the managed identity." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Required. Tags to be applied to the managed identity." - } }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry for the AVM deployment." - } - } - }, - "resources": [ - { + "logAnalyticsWorkspace": { + "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[parameters('name')]", + "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, "name": { - "value": "[parameters('name')]" + "value": "[variables('logAnalyticsWorkspaceResourceName')]" }, "location": { "value": "[parameters('location')]" @@ -23384,6 +19435,12 @@ }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" + }, + "enableReplication": { + "value": "[parameters('enableRedundancy')]" + }, + "replicationLocation": { + "value": "[variables('replicaLocation')]" } }, "template": { @@ -23393,325 +19450,106 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." + "version": "0.42.1.51946", + "templateHash": "9919485194443011422" + } }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, + "parameters": { + "solutionName": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." + "description": "Solution name suffix used to derive the resource name." } }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." } }, - "roleAssignmentType": { + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } + "description": "Tags to apply to the resource." } - } - }, - "parameters": { - "name": { - "type": "string", + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, "metadata": { - "description": "Required. Name of the User Assigned Identity." + "description": "Retention period in days. WAF recommends 365." } }, - "location": { + "skuName": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "PerGB2018", "metadata": { - "description": "Optional. Location for all resources." + "description": "SKU name for the workspace." } }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Public network access for ingestion." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Public network access for query." } }, - "tags": { - "type": "object", + "enableReplication": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true + "description": "Enable workspace replication for redundancy." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "replicationLocation": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Replication location (paired region)." } }, - "isolationScope": { + "dailyQuotaGb": { "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], + "defaultValue": "", "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Data sources for VM monitoring (Windows events, perf counters)." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, + "workspace": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -23719,1075 +19557,3210 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { "value": "[parameters('name')]" }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + "location": { + "value": "[parameters('location')]" }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + "tags": { + "value": "[parameters('tags')]" }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } + "dataRetention": { + "value": "[parameters('retentionInDays')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "diagnosticSettings": { + "value": [ + { + "useThisWorkspace": true + } + ] + }, + "publicNetworkAccessForIngestion": { + "value": "[parameters('publicNetworkAccessForIngestion')]" + }, + "publicNetworkAccessForQuery": { + "value": "[parameters('publicNetworkAccessForQuery')]" + }, + "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", + "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", + "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "1387931959101373036" + "templateHash": "14099489006827800075" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace." + }, + "definitions": { + "diagnosticSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "gallerySolutionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the gallery solutions to be created in the log analytics workspace." + } + }, + "storageInsightsConfigType": { + "type": "object", + "properties": { + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the storage account to be linked." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of tables to be read by the workspace." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the storage insights configuration." + } + }, + "linkedServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked service." + } + }, + "linkedStorageAccountType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked storage account." + } + }, + "savedSearchType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "etag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. The category of the saved search. This helps the user to find a saved search faster." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "functionAlias": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. The query expression for the saved search." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The tags attached to the saved search." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language. The current version is 2 and is the default." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the saved search." + } + }, + "dataExportType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data export." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. The destination of the data export." + } + }, + "enable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the data export." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of table names to export." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data export." + } + }, + "dataSourceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "metadata": { + "description": "Required. The kind of data source." + } + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the event log to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data source." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "plan": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The plan for the table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. The restored logs for the table." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. The schema for the table." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. The search results for the table." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The role assignments for the table." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the custom table." + } }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." + "workspaceFeaturesType": { + "type": "object", + "properties": { + "disableLocalAuth": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable Non-EntraID based Auth. Default is true." + } + }, + "enableDataExport": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that indicate if data should be exported." + } + }, + "enableLogAccessUsingOnlyResourcePermissions": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable log access using only resource permissions. Default is false." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that describes if we want to remove the data after 30 days." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Features of the workspace." + } + }, + "workspaceReplicationType": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Replication properties of the workspace." + } + }, + "_1.columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "description": "The parameters of the table column.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "description": "The data export destination properties.", + "__bicep_imported_from!": { + "sourceTemplate": "data-export/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the restore operation that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "description": "The table schema.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the search job that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" + } + } + } }, "parameters": { - "userAssignedIdentityName": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/storageInsightsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "linkedServices": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedStorageAccountType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + } + }, + "savedSearches": { + "type": "array", + "items": { + "$ref": "#/definitions/savedSearchType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "items": { + "$ref": "#/definitions/dataExportType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "items": { + "$ref": "#/definitions/dataSourceType" + }, + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + "description": "Optional. LAW data sources to configure." } }, - "name": { - "type": "string", + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, "metadata": { - "description": "Required. The name of the secret." + "description": "Optional. LAW custom tables to be deployed." } }, - "audiences": { + "gallerySolutions": { "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." } }, - "issuer": { - "type": "string", + "onboardWorkspaceToSentinel": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." } }, - "subject": { - "type": "string", + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + "description": "Optional. Number of days data will be retained for." } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "-1", + "metadata": { + "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." } - } - ], - "outputs": { - "name": { + }, + "defaultDataCollectionRuleResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "The name of the federated identity credential." - }, - "value": "[parameters('name')]" + "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." + } }, - "resourceId": { + "publicNetworkAccessForIngestion": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], "metadata": { - "description": "The resource ID of the federated identity credential." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } }, - "resourceGroupName": { + "publicNetworkAccessForQuery": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], "metadata": { - "description": "The name of the resource group the federated identity credential was created in." + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "features": { + "$ref": "#/definitions/workspaceFeaturesType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace features." + } + }, + "replication": { + "$ref": "#/definitions/workspaceReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace replication properties." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingType" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "userAssignedIdentity" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', parameters('name')), '2025-04-01').outputs.resourceId.value]" - }, - "principalId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', parameters('name')), '2025-04-01').outputs.principalId.value]" - } - } - } - } - }, - "avmContainerRegistry": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "acrName": { - "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "acrSku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "zoneRedundancy": { - "value": "Disabled" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmContainerRegistryReader').outputs.principalId.value]", - "roleDefinitionIdOrName": "AcrPull", - "principalType": "ServicePrincipal" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableRedundancy": { - "value": "[parameters('enableRedundancy')]" - }, - "replicaLocation": { - "value": "[variables('replicaLocation')]" - }, - "enablePrivateNetworking": { - "value": "[parameters('enablePrivateNetworking')]" - }, - "backendSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", - "privateDnsZoneResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value), createObject('value', ''))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1869938830611166930" - }, - "name": "Container Registry Module" - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "acrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Azure Container Registry." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Required. The location of the Azure Container Registry." - } - }, - "acrSku": { - "type": "string", - "defaultValue": "Basic", - "metadata": { - "description": "Optional. SKU for the Azure Container Registry." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Optional. Public network access setting for the Azure Container Registry." - } - }, - "zoneRedundancy": { - "type": "string", - "defaultValue": "Disabled", - "metadata": { - "description": "Optional. Zone redundancy setting for the Azure Container Registry." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the Container Registry." - } - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry for the AVM deployment." - } - }, - "enableRedundancy": { - "type": "bool", - "metadata": { - "description": "Required. Enable Redundancy for the AVM deployment." - } - }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. The replica location for the Azure Container Registry replication, if redundancy is enabled." - } - }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable private networking for the Container Registry." - } - }, - "backendSubnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Backend subnet resource ID for private endpoints." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Private DNS zone resource ID for Container Registry." - } - } - }, - "resources": { - "avmContainerRegistry": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[parameters('acrName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('acrName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "acrSku": { - "value": "[parameters('acrSku')]" - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - }, - "zoneRedundancy": { - "value": "[parameters('zoneRedundancy')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "replications": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('location', parameters('replicaLocation'), 'name', format('acrrepl{0}', replace(parameters('replicaLocation'), '-', ''))))), createObject('value', null()))]", - "networkRuleSetDefaultAction": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Deny'), createObject('value', 'Allow'))]", - "networkRuleSetIpRules": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray()), createObject('value', null()))]", - "exportPolicyStatus": "[if(parameters('enablePrivateNetworking'), createObject('value', 'disabled'), createObject('value', null()))]", - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-acr-{0}', parameters('acrName')), 'customNetworkInterfaceName', format('nic-acr-{0}', parameters('acrName')), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceId'))), createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'acr-dns-zone-group', 'privateDnsZoneResourceId', parameters('privateDnsZoneResourceId')))), null()), 'subnetResourceId', parameters('backendSubnetResourceId')))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1509121545318808417" - }, - "name": "Azure Container Registries (ACR)", - "description": "This module deploys an Azure Container Registry (ACR)." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "credentialSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" - }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a credential set." - } - }, - "scopeMapsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the scope map." - } - }, - "actions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" }, - "description": "Required. The list of scoped permissions for registry artifacts." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The user friendly description of the scope map." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a scope map." - } - }, - "cacheRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cache rule." - } - }, - "replicationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true }, - "description": "Optional. Tags of the resource." + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } - }, - "zoneRedundancy": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" - }, - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replication." - } - }, - "taskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the task." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", + "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", + "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", + "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]", + "replication": "[parameters('replication')]", + "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" + }, + "identity": "[variables('identity')]" }, - "description": "Optional. The platform properties for the task." - }, - "nullable": true - }, - "step": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + "logAnalyticsWorkspace_diagnosticSettings": { + "copy": { + "name": "logAnalyticsWorkspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The step properties for the task." - }, - "nullable": true - }, - "trigger": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + "logAnalyticsWorkspace_sentinelOnboarding": { + "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", + "type": "Microsoft.SecurityInsights/onboardingStates", + "apiVersion": "2025-09-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "default", + "properties": {}, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { + "copy": { + "name": "logAnalyticsWorkspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "140290971998938797" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14482465616812596213" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedStorageAccounts": { + "copy": { + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" + }, + "storageAccountIds": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14864721709229272590" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": "[parameters('storageAccountIds')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" + }, + "etag": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + }, + "category": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" + }, + "query": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17904092372918022238" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] }, - "description": "Optional. The trigger properties for the task." - }, - "nullable": true - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17943947755417749524" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The status of the task at the time the operation was called." - }, - "nullable": true - }, - "timeout": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." - } - }, - "agentConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + "logAnalyticsWorkspace_dataSources": { + "copy": { + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" + }, + "kind": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "15360290236166491819" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The agent configuration for the task." - }, - "nullable": true - }, - "agentPoolName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." - } - }, - "isSystemTask": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." - } - }, - "logTemplate": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The log template for the task to use when creating logs in Log Analytics." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a task." - } - }, - "tokenType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the token." - } - }, - "scopeMapResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the scope map which defines the permissions for this token." - } - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "18383178824663161801" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The status of the token at the time the operation was called." - }, - "nullable": true - }, - "credentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10255889523646649592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." - } - } - } - }, - "webhookType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "string", - "metadata": { - "description": "Required. The service URI for the webhook to post notifications." - } - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" }, - "description": "Optional. The status of the webhook at the time the operation was called." - }, - "nullable": true - }, - "action": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "customHeaders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" }, - "description": "Optional. Custom headers that will be added to the webhook notifications." - }, - "nullable": true - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a webhook." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "logAnalyticsWorkspaceId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" }, - "memberName": { + "location": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" }, - "privateIPAddress": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + "description": "The principal ID of the system assigned identity." }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } + "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" + }, + "primarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The primary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" + }, + "secondarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The secondary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } - }, - "authCredentialsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } - }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." - } - }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." }, + "value": "[reference('workspace').outputs.resourceId.value]" + }, + "name": { + "type": "string", "metadata": { - "description": "The type for auth credentials.", - "__bicep_imported_from!": { - "sourceTemplate": "credential-set/main.bicep" - } - } + "description": "Name of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.name.value]" }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." }, + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + } + }, + "applicationInsights": { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appi-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "retentionInDays": { + "value": 365 + }, + "kind": { + "value": "web" + }, + "disableIpMasking": { + "value": false + }, + "flowType": { + "value": "Bluefield" + }, + "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17358780145253914698" }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance." + }, + "definitions": { "diagnosticSettingFullType": { "type": "object", "properties": { @@ -24906,7 +22879,7 @@ "metadata": { "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -24943,904 +22916,2836 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "managedIdentityAllType": { + "roleAssignmentType": { "type": "object", "properties": { - "systemAssigned": { - "type": "bool", + "name": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "flowType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." + } + }, + "requestSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Purge data immediately after 30 days." + } + }, + "ingestionMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ApplicationInsights", + "ApplicationInsightsWithDiagnosticSettings", + "LogAnalytics" + ], + "metadata": { + "description": "Optional. Indicates the flow of the ingestion." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/components@2020-02-02#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]", + "Flow_Type": "[parameters('flowType')]", + "Request_Source": "[parameters('requestSource')]", + "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", + "IngestionMode": "[parameters('ingestionMode')]" + } + }, + "appInsights_roleAssignments": { + "copy": { + "name": "appInsights_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_diagnosticSettings": { + "copy": { + "name": "appInsights_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5059808225314360251" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } } } }, + "dependsOn": [ + "appInsights" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights component was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference('appInsights').AppId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "avmManagedIdentity": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Azure region for the resource." } }, - "managedIdentityOnlySysAssignedType": { + "tags": { "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Tags to apply to the resource." } }, - "privateEndpointSingleServiceType": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('identityName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" + "tags": { + "value": "[parameters('tags')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } } - }, - "parameters": { - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. Name of your Azure Container Registry." - } - }, - "acrAdminUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable admin user that have push / pull permission to the registry." - } - }, - "location": { + ], + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "description": "Resource ID of the managed identity." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "autoGeneratedDomainNameLabelScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse", - "Unsecure" - ], - "metadata": { - "description": "Optional. The domain name label reuse scope." - } + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "roleAssignmentMode": { + "principalId": { "type": "string", - "nullable": true, - "allowedValues": [ - "AbacRepositoryPermissions", - "LegacyRegistryPermissions" - ], "metadata": { - "description": "Optional. The registry permissions role assignment mode." - } + "description": "Principal ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" }, - "acrSku": { + "clientId": { "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Premium", - "Standard" - ], "metadata": { - "description": "Optional. Tier of your Azure container registry." - } + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" }, - "exportPolicyStatus": { + "name": { "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], "metadata": { - "description": "Optional. The value that indicates whether the export policy is enabled or not." - } - }, - "quarantinePolicyStatus": { + "description": "Name of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + "avmContainerRegistry": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "acrPullPrincipalIds": { + "value": [ + "[reference('avmContainerRegistryReader').outputs.principalId.value]" + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8138805991948000285" + } + }, + "parameters": { + "solutionName": { "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], "metadata": { - "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + "description": "Solution name used for naming convention." } }, - "trustPolicyStatus": { + "name": { "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", "metadata": { - "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + "description": "Name of the container registry." } }, - "retentionPolicyStatus": { + "location": { "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the retention policy is enabled or not." - } - }, - "retentionPolicyDays": { - "type": "int", - "defaultValue": 15, "metadata": { - "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + "description": "Azure region for deployment." } }, - "azureADAuthenticationAsArmPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + "description": "Resource tags." } }, - "softDeletePolicyStatus": { + "sku": { "type": "string", - "defaultValue": "disabled", + "defaultValue": "Premium", "allowedValues": [ - "disabled", - "enabled" + "Basic", + "Standard", + "Premium" ], "metadata": { - "description": "Optional. Soft Delete policy status. Default is disabled." - } - }, - "softDeletePolicyDays": { - "type": "int", - "defaultValue": 7, - "metadata": { - "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + "description": "SKU for the container registry." } }, - "dataEndpointEnabled": { + "adminUserEnabled": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + "description": "Enable admin user for the registry." } }, "publicNetworkAccess": { "type": "string", - "nullable": true, + "defaultValue": "Enabled", "allowedValues": [ "Enabled", "Disabled" ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "networkRuleBypassOptions": { - "type": "string", - "defaultValue": "AzureServices", - "allowedValues": [ - "AzureServices", - "None" - ], - "metadata": { - "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + "description": "Public network access setting." } }, - "networkRuleSetDefaultAction": { + "exportPolicyStatus": { "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], + "defaultValue": "enabled", "metadata": { - "description": "Optional. The default action of allow or deny when no other rules match." + "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." } }, - "networkRuleSetIpRules": { + "acrPullPrincipalIds": { "type": "array", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." + "description": "Principal IDs to assign AcrPull role." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + "description": "Enable private networking." } }, - "zoneRedundancy": { + "privateEndpointSubnetId": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } - }, - "replications": { - "type": "array", - "items": { - "$ref": "#/definitions/replicationType" - }, - "nullable": true, + "defaultValue": "", "metadata": { - "description": "Optional. All replications to create." + "description": "Subnet resource ID for private endpoint." } }, - "webhooks": { + "privateDnsZoneResourceIds": { "type": "array", - "items": { - "$ref": "#/definitions/webhookType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All webhooks to create." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Private DNS zone resource IDs for private endpoint." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." - } - }, - "anonymousPullEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "cacheRules": { - "type": "array", - "items": { - "$ref": "#/definitions/cacheRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cache Rules." - } - }, - "credentialSets": { - "type": "array", - "items": { - "$ref": "#/definitions/credentialSetType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Credential Sets." - } - }, - "scopeMaps": { - "type": "array", - "items": { - "$ref": "#/definitions/scopeMapsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Scope maps setting." - } - }, - "tokens": { - "type": "array", - "items": { - "$ref": "#/definitions/tokenType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tokens to create for the container registry." - } - }, - "tasks": { - "type": "array", - "items": { - "$ref": "#/definitions/taskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of ACR Tasks to create." + "description": "Enable Azure telemetry collection." } } }, "variables": { "copy": [ { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "name": "roleAssignments", + "count": "[length(parameters('acrPullPrincipalIds'))]", + "input": { + "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", + "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", + "principalType": "ServicePrincipal" + } + }, + { + "name": "dnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" + } } ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", - "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", - "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", - "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", - "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", - "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", - "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", - "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", - "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", - "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", - "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" + "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "registry": { - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-06-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('acrSku')]" - }, - "properties": { - "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", - "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", - "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", - "roleAssignmentMode": "[parameters('roleAssignmentMode')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", - "policies": { - "azureADAuthenticationAsArmPolicy": { - "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "acrSku": { + "value": "[parameters('sku')]" + }, + "acrAdminUserEnabled": { + "value": "[parameters('adminUserEnabled')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", - "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", - "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", - "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", - "softDeletePolicy": { - "retentionDays": "[parameters('softDeletePolicyDays')]", - "status": "[parameters('softDeletePolicyStatus')]" + "exportPolicyStatus": { + "value": "[parameters('exportPolicyStatus')]" + }, + "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[variables('privateEndpointConfig')]" } }, - "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", - "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", - "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", - "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", - "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "registry_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_diagnosticSettings": { - "copy": { - "name": "registry_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1509121545318808417" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR)." }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "credentialSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a credential set." + } + }, + "scopeMapsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" + }, + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a scope map." + } + }, + "cacheRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cache rule." + } + }, + "replicationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" + }, + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replication." + } + }, + "taskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties for the task." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The step properties for the task." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The trigger properties for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the task at the time the operation was called." + }, + "nullable": true + }, + "timeout": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The agent configuration for the task." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." + } + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The log template for the task to use when creating logs in Log Analytics." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a task." + } + }, + "tokenType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map which defines the permissions for this token." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" + }, + "description": "Optional. The status of the token at the time the operation was called." + }, + "nullable": true + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." + } + } + } + }, + "webhookType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the webhook at the time the operation was called." + }, + "nullable": true + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + }, + "description": "Optional. Custom headers that will be added to the webhook notifications." + }, + "nullable": true + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a webhook." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "description": "The type for auth credentials.", + "__bicep_imported_from!": { + "sourceTemplate": "credential-set/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_roleAssignments": { - "copy": { - "name": "registry_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_scopeMaps": { - "copy": { - "name": "registry_scopeMaps", - "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" - }, - "actions": { - "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" }, - "registryName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3787322352564227867" + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "autoGeneratedDomainNameLabelScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse", + "Unsecure" + ], + "metadata": { + "description": "Optional. The domain name label reuse scope." + } + }, + "roleAssignmentMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AbacRepositoryPermissions", + "LegacyRegistryPermissions" + ], + "metadata": { + "description": "Optional. The registry permissions role assignment mode." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } }, - "name": "Container Registries scope maps", - "description": "This module deploys an Azure Container Registry (ACR) scope map." - }, - "parameters": { - "registryName": { - "type": "string", + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." } }, - "name": { + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { "type": "string", - "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "Optional. The name of the scope map." + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." } }, - "actions": { + "replications": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/replicationType" }, + "nullable": true, "metadata": { - "description": "Required. The list of scoped permissions for registry artifacts." + "description": "Optional. All replications to create." } }, - "description": { - "type": "string", + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/webhookType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. The user friendly description of the scope map." + "description": "Optional. The managed identity definition for this resource." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "items": { + "$ref": "#/definitions/cacheRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialSetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/scopeMapsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Scope maps setting." + } + }, + "tokens": { + "type": "array", + "items": { + "$ref": "#/definitions/tokenType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tokens to create for the container registry." + } + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/definitions/taskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of ACR Tasks to create." + } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", + "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", + "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", + "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" + }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -25856,5182 +25761,6040 @@ } } }, - "registry": { + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" }, - "scopeMap": { - "type": "Microsoft.ContainerRegistry/registries/scopeMaps", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, "properties": { - "actions": "[parameters('actions')]", - "description": "[parameters('description')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the scope map." + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", + "roleAssignmentMode": "[parameters('roleAssignmentMode')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" }, - "value": "[parameters('name')]" + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the scope map was created in." + "registry_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "registry" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the scope map." + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_replications": { - "copy": { - "name": "registry_replications", - "count": "[length(coalesce(parameters('replications'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" - }, - "regionEndpointEnabled": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" - }, - "zoneRedundancy": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "6219097750044645017" - }, - "name": "Azure Container Registry (ACR) Replications", - "description": "This module deploys an Azure Container Registry (ACR) Replication." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "registry" + ] }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" + ] }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. Tags of the resource." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3787322352564227867" + }, + "name": "Container Registries scope maps", + "description": "This module deploys an Azure Container Registry (ACR) scope map." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } + "dependsOn": [ + "registry" + ] }, - "zoneRedundancy": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6219097750044645017" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13412699468141336519" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set." + }, + "definitions": { + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for auth credentials." + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" } } } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "replication": { - "type": "Microsoft.ContainerRegistry/registries/replications", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", - "zoneRedundancy": "[parameters('zoneRedundancy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the replication." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the replication." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the replication was created in." }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "registry" + ] }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" }, - "value": "[reference('replication', '2025-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_credentialSets": { - "copy": { - "name": "registry_credentialSets", - "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "managedIdentities": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" - }, - "authCredentials": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" - }, - "loginServer": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13412699468141336519" - }, - "name": "Container Registries Credential Sets", - "description": "This module deploys an ACR Credential Set." - }, - "definitions": { - "authCredentialsType": { - "type": "object", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for auth credentials." - } - }, - "managedIdentityOnlySysAssignedType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1319901650921923538" + }, + "name": "Container Registry Cache", + "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "cacheRule": { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "dependsOn": [ + "registry", + "registry_credentialSets" + ] }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" + "registry_tokens": { + "copy": { + "name": "registry_tokens", + "count": "[length(coalesce(parameters('tokens'), createArray()))]" }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "scopeMapResourceId": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5970335582661416899" + }, + "name": "Container Registries Tokens", + "description": "Deploys an Azure Container Registry (ACR) Token." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map to which the token will be associated with." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the token. Default is enabled." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + }, + "description": "Optional. The credentials associated with the token for authentication." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "credentialSet": { - "type": "Microsoft.ContainerRegistry/registries/credentialSets", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", - "properties": { - "authCredentials": "[parameters('authCredentials')]", - "loginServer": "[parameters('loginServer')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Credential Set." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Credential Set." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Credential Set." + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "token": { + "type": "Microsoft.ContainerRegistry/registries/tokens", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "scopeMapId": "[parameters('scopeMapResourceId')]", + "status": "[parameters('status')]", + "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the token." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the token was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the token." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" + } + } + } }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + "dependsOn": [ + "registry", + "registry_scopeMaps" + ] }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." + "registry_tasks": { + "copy": { + "name": "registry_tasks", + "count": "[length(coalesce(parameters('tasks'), createArray()))]" }, - "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_cacheRules": { - "copy": { - "name": "registry_cacheRules", - "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "registryName": { - "value": "[parameters('name')]" - }, - "sourceRepository": { - "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" - }, - "targetRepository": { - "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" - }, - "credentialSetResourceId": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1319901650921923538" - }, - "name": "Container Registry Cache", - "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "defaultValue": "[parameters('sourceRepository')]", - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "platform": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" + }, + "step": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" + }, + "trigger": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" + }, + "timeout": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" + }, + "agentConfiguration": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" + }, + "agentPoolName": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" + }, + "isSystemTask": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" + }, + "logTemplate": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2468771835002458415" + }, + "name": "Container Registries Tasks", + "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." + }, + "definitions": { + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties against which the task has to run." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The properties that describe all triggers for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. The current status of task." + } + }, + "timeout": { + "type": "int", + "defaultValue": 3600, + "minValue": 300, + "maxValue": 28800, + "metadata": { + "description": "Optional. Run timeout in seconds." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The machine configuration of the run agent." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The dedicated agent pool for the task." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" + }, + "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + }, + "nullable": true + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The value of this property indicates whether the task resource is system task or not." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The template that describes the repository and tag information for run log artifact." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "task": { + "type": "Microsoft.ContainerRegistry/registries/tasks", + "apiVersion": "2025-03-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "agentConfiguration": "[parameters('agentConfiguration')]", + "agentPoolName": "[parameters('agentPoolName')]", + "credentials": "[parameters('credentials')]", + "isSystemTask": "[parameters('isSystemTask')]", + "logTemplate": "[parameters('logTemplate')]", + "platform": "[parameters('platform')]", + "status": "[parameters('status')]", + "step": "[parameters('step')]", + "timeout": "[parameters('timeout')]", + "trigger": "[parameters('trigger')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the task." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the task was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the task." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('task', '2025-03-01-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" } } } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "cacheRule": { - "type": "Microsoft.ContainerRegistry/registries/cacheRules", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "sourceRepository": "[parameters('sourceRepository')]", - "targetRepository": "[parameters('targetRepository')]", - "credentialSetResourceId": "[parameters('credentialSetResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Cache Rule." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Cache Rule." }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "registry" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cache Rule." + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry", - "registry_credentialSets" - ] - }, - "registry_tokens": { - "copy": { - "name": "registry_tokens", - "count": "[length(coalesce(parameters('tokens'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "scopeMapResourceId": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" - }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "5970335582661416899" - }, - "name": "Container Registries Tokens", - "description": "Deploys an Azure Container Registry (ACR) Token." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. The name of the token." - } - }, - "scopeMapResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the scope map to which the token will be associated with." - } - }, - "status": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The status of the token. Default is enabled." - } - }, - "credentials": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } }, - "description": "Optional. The credentials associated with the token for authentication." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3200175097987099858" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "securestring", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2025-11-01', 'full').location]" + } + } + } }, - "nullable": true + "dependsOn": [ + "registry" + ] }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "token": { - "type": "Microsoft.ContainerRegistry/registries/tokens", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "scopeMapId": "[parameters('scopeMapResourceId')]", - "status": "[parameters('status')]", - "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" - } + }, + "dependsOn": [ + "registry", + "registry_replications" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the token." + "description": "The Name of the Azure container registry." }, "value": "[parameters('name')]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the token was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the token." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry", - "registry_scopeMaps" - ] - }, - "registry_tasks": { - "copy": { - "name": "registry_tasks", - "count": "[length(coalesce(parameters('tasks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "registryName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "platform": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" - }, - "step": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" - }, - "trigger": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" - }, - "timeout": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" - }, - "agentConfiguration": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" - }, - "agentPoolName": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" - }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" - }, - "isSystemTask": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" - }, - "logTemplate": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" - }, - "managedIdentities": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2468771835002458415" - }, - "name": "Container Registries Tasks", - "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." - }, - "definitions": { - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. The name of the task." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" - }, - "description": "Optional. The platform properties against which the task has to run." - }, - "nullable": true - }, - "step": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" - }, - "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." - }, - "nullable": true - }, - "trigger": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" - }, - "description": "Optional. The properties that describe all triggers for the task." - }, - "nullable": true - }, - "status": { + "loginServer": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], "metadata": { - "description": "Optional. The current status of task." - } + "description": "The reference to the Azure container registry." + }, + "value": "[reference('registry').loginServer]" }, - "timeout": { - "type": "int", - "defaultValue": 3600, - "minValue": 300, - "maxValue": 28800, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "Optional. Run timeout in seconds." - } + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" }, - "agentConfiguration": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" - }, - "description": "Optional. The machine configuration of the run agent." + "description": "The resource ID of the Azure container registry." }, - "nullable": true + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" }, - "agentPoolName": { + "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The dedicated agent pool for the task." - } + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" }, - "credentials": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" - }, - "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + "description": "The location the resource was deployed into." }, - "nullable": true + "value": "[reference('registry', '2025-06-01-preview', 'full').location]" }, - "isSystemTask": { - "type": "bool", - "nullable": true, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", "metadata": { - "description": "Optional. The value of this property indicates whether the task resource is system task or not." + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" } }, - "logTemplate": { - "type": "string", - "nullable": true, + "credentialSetsResourceIds": { + "type": "array", "metadata": { - "description": "Optional. The template that describes the repository and tag information for run log artifact." + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "The private endpoints of the Azure container registry." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "avmContainerRegistryReader", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", + "virtualNetwork" + ] + }, + "avmStorageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "minimumTlsVersion": { + "value": "TLS1_2" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", + "ipRules": [] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "supportsHttpsTrafficOnly": { + "value": true + }, + "accessTier": { + "value": "Hot" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1254456195180100771" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } } } }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoints output." + } + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "task": { - "type": "Microsoft.ContainerRegistry/registries/tasks", - "apiVersion": "2025-03-01-preview", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": { - "agentConfiguration": "[parameters('agentConfiguration')]", - "agentPoolName": "[parameters('agentPoolName')]", - "credentials": "[parameters('credentials')]", - "isSystemTask": "[parameters('isSystemTask')]", - "logTemplate": "[parameters('logTemplate')]", - "platform": "[parameters('platform')]", - "status": "[parameters('status')]", - "step": "[parameters('step')]", - "timeout": "[parameters('timeout')]", - "trigger": "[parameters('trigger')]" } } }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the task." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the task was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the task." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network configuration." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey1 secret name to create." + } + }, + "connectionString1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString1 secret name to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey2 secret name to create." + } + }, + "connectionString2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString2 secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the exported secrets." + } + }, + "localUserType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a local user." + } + }, + "blobServiceType": { + "type": "object", + "properties": { + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/blobCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "versionDeletePolicyDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a blob service." + } + }, + "fileServiceType": { + "type": "object", + "properties": { + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('task', '2025-03-01-preview', 'full').location]" + "description": "Optional. Protocol settings for file service." + }, + "nullable": true + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" - } + "description": "Optional. The service properties for soft delete." + }, + "nullable": true + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/fileCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "dependsOn": [ - "registry" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type of a file service." + } }, - "registry_webhooks": { - "copy": { - "name": "registry_webhooks", - "count": "[length(coalesce(parameters('webhooks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "queueServiceType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "action": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" }, - "customHeaders": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/queueCorsRuleType" }, - "scope": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" }, - "status": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a queue service." + } + }, + "tableServiceType": { + "type": "object", + "properties": { + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" }, - "serviceUri": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/tableCorsRuleType" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a table service." + } + }, + "objectReplicationPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "destinationStorageAccountResourceId": { + "type": "string", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3200175097987099858" - }, - "name": "Azure Container Registry (ACR) Webhooks", - "description": "This module deploys an Azure Container Registry (ACR) Webhook." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}webhook', parameters('registryName'))]", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "securestring", - "metadata": { - "description": "Required. The service URI for the webhook to post notifications." - } - }, - "status": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The status of the webhook at the time the operation was called." - } - }, - "action": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [ - "chart_delete", - "chart_push", - "delete", - "push", - "quarantine" - ], - "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "customHeaders": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Custom headers that will be added to the webhook notifications." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "webhook": { - "type": "Microsoft.ContainerRegistry/registries/webhooks", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "actions": "[parameters('action')]", - "customHeaders": "[parameters('customHeaders')]", - "scope": "[parameters('scope')]", - "serviceUri": "[parameters('serviceUri')]", - "status": "[parameters('status')]" - } - } + "description": "Required. The resource ID of the destination storage account." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the webhook." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the webhook." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Azure container registry." - }, - "value": "[resourceGroup().name]" - }, - "actions": { - "type": "array", - "metadata": { - "description": "The actions of the webhook." - }, - "value": "[reference('webhook').actions]" - }, - "status": { - "type": "string", - "metadata": { - "description": "The status of the webhook." - }, - "value": "[reference('webhook').status]" - }, - "provistioningState": { - "type": "string", - "metadata": { - "description": "The provisioning state of the webhook." - }, - "value": "[reference('webhook').provisioningState]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('webhook', '2025-11-01', 'full').location]" - } + "metadata": { + "description": "Required. The storage account object replication rules." } } }, - "dependsOn": [ - "registry" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy." + } }, - "registry_privateEndpoints": { - "copy": { - "name": "registry_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "_1.immutabilityPolicyType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/container/main.bicep" + } + } + }, + "_2.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { + "memberName": { "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." } }, - "location": { + "privateIPAddress": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "blobCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/_1.immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type of a storage container.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." } }, - "dependsOn": [ - "privateEndpoint" - ] + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } } }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "fileCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a file share.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { "type": "array", "items": { "type": "string" }, + "nullable": true, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "description": "Optional. The prefix to match for the replication policy rule." + } }, - "groupId": { + "minCreationTime": { "type": "string", "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "description": "Optional. The minimum creation time to match for the replication policy rule." + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "object-replication-policy/policy/main.bicep" + } + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "queueCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a queue.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_2.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "tableCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." } } }, - "dependsOn": [ - "registry", - "registry_replications" - ] + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a table.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep" + } + } } }, - "outputs": { + "parameters": { "name": { "type": "string", + "maxLength": 24, "metadata": { - "description": "The Name of the Azure container registry." - }, - "value": "[parameters('name')]" + "description": "Required. Name of the Storage Account. Must be lower-case." + } }, - "loginServer": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "The reference to the Azure container registry." - }, - "value": "[reference('registry').loginServer]" + "description": "Optional. Location for all resources." + } }, - "resourceGroupName": { + "extendedLocationZone": { "type": "string", + "nullable": true, "metadata": { - "description": "The name of the Azure container registry." + "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "value": "[resourceGroup().name]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } }, - "resourceId": { + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], "metadata": { - "description": "The resource ID of the Azure container registry." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + "description": "Optional. Type of Storage Account to create." + } }, - "systemAssignedMIPrincipalId": { + "skuName": { "type": "string", - "nullable": true, + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS", + "Standard_GRS", + "Standard_GZRS", + "Standard_RAGRS", + "Standard_RAGZRS", + "StandardV2_LRS", + "StandardV2_ZRS", + "StandardV2_GRS", + "StandardV2_GZRS", + "Premium_LRS", + "Premium_ZRS", + "PremiumV2_LRS", + "PremiumV2_ZRS" + ], "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" + "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." + } }, - "location": { + "accessTier": { "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "Cold" + ], "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('registry', '2025-06-01-preview', 'full').location]" + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } }, - "credentialSetsSystemAssignedMIPrincipalIds": { - "type": "array", + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" + "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." } }, - "credentialSetsResourceIds": { - "type": "array", + "azureFilesIdentityBasedAuthentication": { + "type": "object", "metadata": { - "description": "The Resource IDs of the ACR Credential Sets." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" + }, + "description": "Optional. Provides the identity based authentication settings for Azure Files." }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" + "nullable": true + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." } }, "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "$ref": "#/definitions/privateEndpointMultiServiceType" }, + "nullable": true, "metadata": { - "description": "The private endpoints of the Azure container registry." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "value": "[reference('avmContainerRegistry').outputs.name.value]" - }, - "resourceId": { - "type": "string", - "value": "[reference('avmContainerRegistry').outputs.resourceId.value]" - }, - "loginServer": { - "type": "string", - "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" - } - } - } - }, - "dependsOn": [ - "avmContainerRegistryReader", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", - "virtualNetwork" - ] - }, - "avmStorageAccount": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "minimumTlsVersion": { - "value": "TLS1_2" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", - "ipRules": [] - } - }, - "requireInfrastructureEncryption": { - "value": true - }, - "supportsHttpsTrafficOnly": { - "value": true - }, - "accessTier": { - "value": "Hot" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1254456195180100771" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + }, + "managementPolicyRules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoints output." - } - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } + "description": "Optional. The Storage Account ManagementPolicies Rules." }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network configuration." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey1 secret name to create." - } - }, - "connectionString1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString1 secret name to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey2 secret name to create." - } - }, - "connectionString2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString2 secret name to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the exported secrets." - } - }, - "localUserType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The local user home directory." - } - }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" - }, - "metadata": { - "description": "Required. The permission scopes of the local user." - } - }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a local user." - } - }, - "blobServiceType": { - "type": "object", - "properties": { - "automaticSnapshotPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." - } - }, - "changeFeedEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." - } - }, - "changeFeedRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 146000, - "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." - } - }, - "containerDeleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." - } - }, - "containerDeleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." - } - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/blobCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "defaultServiceVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." - } - }, - "deleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob soft delete." - } - }, - "deleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." - } - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "isVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." - } - }, - "versionDeletePolicyDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." - } - }, - "lastAccessTimeTrackingPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." - } - }, - "restorePolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." - } - }, - "restorePolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Blob containers to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a blob service." - } - }, - "fileServiceType": { - "type": "object", - "properties": { - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" - }, - "description": "Optional. Protocol settings for file service." - }, - "nullable": true - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" - }, - "description": "Optional. The service properties for soft delete." - }, - "nullable": true - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/fileCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a file service." - } - }, - "queueServiceType": { - "type": "object", - "properties": { - "queues": { - "type": "array", - "items": { - "$ref": "#/definitions/queueType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Queues to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/queueCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a queue service." - } - }, - "tableServiceType": { - "type": "object", - "properties": { - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/tableCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a table service." - } - }, - "objectReplicationPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." - } - }, - "destinationStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the destination storage account." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. The storage account object replication rules." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy." - } - }, - "_1.immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - } - }, - "metadata": { - "description": "The type for an immutability policy.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/container/main.bicep" - } - } - }, - "_2.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "nullable": true + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." } }, - "memberName": { + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { "type": "string", + "nullable": true, + "allowedValues": [ + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "$ref": "#/definitions/blobServiceType", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "$ref": "#/definitions/fileServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "$ref": "#/definitions/queueServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "$ref": "#/definitions/tableServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." } }, - "privateIPAddress": { + "minimumTlsVersion": { "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_2", + "TLS1_3" + ], "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "blobCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "containerType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } - }, - "immutabilityPolicy": { - "$ref": "#/definitions/_1.immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" }, - "description": "Optional. A name-value pair to associate with the container as metadata." - }, - "nullable": true - }, - "publicAccess": { - "type": "string", - "allowedValues": [ - "Blob", - "Container", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type of a storage container.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + }, + "localUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/localUserType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "fileCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." - } - }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, - "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a file share.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, "nullable": true, "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "minCreationTime": { + "allowedCopyScope": { "type": "string", "nullable": true, + "allowedValues": [ + "AAD", + "PrivateLink" + ], "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "description": "The type of an object replication policy rule.", - "__bicep_imported_from!": { - "sourceTemplate": "object-replication-policy/policy/main.bicep" - } - } - }, - "permissionScopeType": { - "type": "object", - "properties": { - "permissions": { - "type": "string", - "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." - } - }, - "resourceName": { - "type": "string", - "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "queueCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "queueType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the queue." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a queue.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_2.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "sshAuthorizedKeyType": { - "type": "object", - "properties": { - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description used to store the function/usage of the key." - } - }, - "key": { - "type": "securestring", - "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } - } - }, - "tableCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a table.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "extendedLocationZone": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "kind": { - "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_ZRS", - "Standard_GRS", - "Standard_GZRS", - "Standard_RAGRS", - "Standard_RAGZRS", - "StandardV2_LRS", - "StandardV2_ZRS", - "StandardV2_GRS", - "StandardV2_GZRS", - "Premium_LRS", - "Premium_ZRS", - "PremiumV2_LRS", - "PremiumV2_ZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "Cold" - ], - "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." - } - }, - "largeFileSharesState": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" - }, - "description": "Optional. Provides the identity based authentication settings for Azure Files." - }, - "nullable": true - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } - }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "managementPolicyRules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Optional. The Storage Account ManagementPolicies Rules." - }, - "nullable": true - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, - "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." - } - }, - "customDomainName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." - } - }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." - } - }, - "dnsEndpointType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "$ref": "#/definitions/blobServiceType", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "$ref": "#/definitions/fileServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "$ref": "#/definitions/queueServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "$ref": "#/definitions/tableServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. Table service and tables to create." - } - }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_2", - "TLS1_3" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." - } - }, - "enableSftp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "localUsers": { - "type": "array", - "items": { - "$ref": "#/definitions/localUserType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Local users to deploy for SFTP authentication." - } - }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables local users feature, if set to true." - } - }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "allowedCopyScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AAD", - "PrivateLink" - ], - "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "sasExpirationAction": { - "type": "string", - "defaultValue": "Log", - "allowedValues": [ - "Block", - "Log" - ], - "metadata": { - "description": "Optional. The SAS expiration action. Allowed values are Block and Log." - } - }, - "keyType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], - "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "immutableStorageWithVersioning": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" - }, - "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." - }, - "nullable": true - }, - "objectReplicationPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Object replication policies for the storage account." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", - "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2025-05-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "sasExpirationAction": { + "type": "string", + "defaultValue": "Log", + "allowedValues": [ + "Block", + "Log" + ], + "metadata": { + "description": "Optional. The SAS expiration action. Allowed values are Block and Log." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "immutableStorageWithVersioning": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" + }, + "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." + }, + "nullable": true + }, + "objectReplicationPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Object replication policies for the storage account." + } } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_roleAssignments": { - "copy": { - "name": "storageAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2025-05-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } }, - "nullable": true + "dependsOn": [ + "storageAccount" + ] }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[variables('formattedManagementPolicies')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4000605059554016072" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Required. The Storage Account ManagementPolicies Rules." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" } } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "storageAccount", + "storageAccount_blobServices" ] }, - "privateEndpoint_roleAssignments": { + "storageAccount_localUsers": { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "name": "storageAccount_localUsers", + "count": "[length(coalesce(parameters('localUsers'), createArray()))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1801226901235196767" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } }, "dependsOn": [ - "privateEndpoint" + "storageAccount" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "storageAccountName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" } }, "template": { @@ -31041,1235 +31804,2222 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "version": "0.41.2.15936", + "templateHash": "468225492069709453" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." }, "definitions": { - "privateDnsZoneGroupConfigType": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a storage container." + } + }, + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "privateDnsZoneResourceId": { + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "container/main.bicep" + } } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "roleAssignmentType": { + "type": "object", "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_managementPolicies": { - "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "rules": { - "value": "[variables('formattedManagementPolicies')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4000605059554016072" - }, - "name": "Storage Account Management Policies", - "description": "This module deploys a Storage Account Management Policy." - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Required. The Storage Account ManagementPolicies Rules." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - { - "type": "Microsoft.Storage/storageAccounts/managementPolicies", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", - "properties": { - "policy": { - "rules": "[parameters('rules')]" - } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed management policy." - }, - "value": "default" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed management policy." - }, - "value": "default" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed management policy." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] - }, - "storageAccount_localUsers": { - "copy": { - "name": "storageAccount_localUsers", - "count": "[length(coalesce(parameters('localUsers'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" - }, - "hasSshKey": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" - }, - "hasSshPassword": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" - }, - "permissionScopes": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" - }, - "hasSharedKey": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" - }, - "homeDirectory": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" - }, - "sshAuthorizedKeys": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1801226901235196767" - }, - "name": "Storage Account Local Users", - "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." - }, - "definitions": { - "sshAuthorizedKeyType": { - "type": "object", - "properties": { - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description used to store the function/usage of the key." - } - }, - "key": { - "type": "securestring", - "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "permissionScopeType": { - "type": "object", - "properties": { - "permissions": { - "type": "string", - "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." - } - }, - "resourceName": { - "type": "string", - "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The local user home directory." - } - }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" - }, - "metadata": { - "description": "Required. The permission scopes of the local user." - } - }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } } - } - } - } - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "localUsers": { - "type": "Microsoft.Storage/storageAccounts/localUsers", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "hasSharedKey": "[parameters('hasSharedKey')]", - "hasSshKey": "[parameters('hasSshKey')]", - "hasSshPassword": "[parameters('hasSshPassword')]", - "homeDirectory": "[parameters('homeDirectory')]", - "permissionScopes": "[parameters('permissionScopes')]", - "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed local user." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed local user." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed local user." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_blobServices": { - "condition": "[not(empty(parameters('blobServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "containers": { - "value": "[tryGet(parameters('blobServices'), 'containers')]" - }, - "automaticSnapshotPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" - }, - "changeFeedEnabled": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" - }, - "changeFeedRetentionInDays": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" - }, - "containerDeleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" - }, - "containerDeleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" - }, - "corsRules": { - "value": "[tryGet(parameters('blobServices'), 'corsRules')]" - }, - "defaultServiceVersion": { - "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" - }, - "deleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" - }, - "deleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" - }, - "isVersioningEnabled": { - "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" - }, - "lastAccessTimeTrackingPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" - }, - "restorePolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" - }, - "restorePolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "468225492069709453" - }, - "name": "Storage Account blob Services", - "description": "This module deploys a Storage Account Blob Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" + "variables": { + "enableReferencedModulesTelemetry": false, + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[parameters('defaultServiceVersion')]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "273904034769611992" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an immutability policy." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "defaultValue": {} + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "container_immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15304742179563677019" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "blobServices" + ] + } }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } + "dependsOn": [ + "storageAccount" + ] }, - "containerType": { - "type": "object", + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + }, + "corsRules": { + "value": "[tryGet(parameters('fileServices'), 'corsRules')]" } }, - "metadata": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17583198711200998285" }, - "description": "Optional. A name-value pair to associate with the container as metadata." + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." }, - "nullable": true - }, - "publicAccess": { - "type": "string", - "allowedValues": [ - "Blob", - "Container", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a storage container." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a file share." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "defaultValue": {} + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "defaultValue": { + "enabled": true, + "days": 7 + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - } - }, - "metadata": { - "description": "The type for an immutability policy.", - "__bicep_imported_from!": { - "sourceTemplate": "container/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "automaticSnapshotPolicyEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." - } - }, - "changeFeedEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." - } - }, - "changeFeedRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 146000, - "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." - } - }, - "containerDeleteRetentionPolicyEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." - } - }, - "containerDeleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." - } - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "defaultServiceVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." - } - }, - "deleteRetentionPolicyEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. The blob service properties for blob soft delete." - } - }, - "deleteRetentionPolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." - } - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "isVersioningEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." - } - }, - "lastAccessTimeTrackingPolicyEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." - } - }, - "restorePolicyEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." - } - }, - "restorePolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, - "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Blob containers to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false, - "name": "default" - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "blobServices": { - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", - "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", - "containerDeleteRetentionPolicy": { - "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", - "days": "[parameters('containerDeleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" - }, - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "defaultServiceVersion": "[parameters('defaultServiceVersion')]", - "deleteRetentionPolicy": { - "enabled": "[parameters('deleteRetentionPolicyEnabled')]", - "days": "[parameters('deleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" - }, - "isVersioningEnabled": "[parameters('isVersioningEnabled')]", - "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", - "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "blobServices_diagnosticSettings": { - "copy": { - "name": "blobServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "provisionedBandwidthMibps": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + }, + "provisionedIops": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10353179772982843397" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]", + "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", + "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "blobServices" + "storageAccount" ] }, - "blobServices_container": { - "copy": { - "name": "blobServices_container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" - }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -32277,43 +34027,16 @@ "mode": "Incremental", "parameters": { "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "blobServiceName": { - "value": "[variables('name')]" - }, - "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" - }, - "defaultEncryptionScope": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" - }, - "denyEncryptionScopeOverride": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" - }, - "enableNfsV3AllSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" - }, - "enableNfsV3RootSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" - }, - "immutableStorageWithVersioningEnabled": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" - }, - "publicAccess": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + "value": "[parameters('name')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" }, - "immutabilityPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" } }, "template": { @@ -32324,40 +34047,227 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "273904034769611992" + "templateHash": "9644461291744477521" }, - "name": "Storage Account Blob Containers", - "description": "This module deploys a Storage Account Blob Container." + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." }, "definitions": { - "immutabilityPolicyType": { + "corsRuleType": { "type": "object", "properties": { - "immutabilityPeriodSinceCreationInDays": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a queue." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." } }, - "allowProtectedAppendWrites": { - "type": "bool", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "allowProtectedAppendWritesAll": { - "type": "bool", + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for an immutability policy." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, "roleAssignmentType": { @@ -32444,200 +34354,105 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "blobServiceName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } - }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. A name-value pair to associate with the container as metadata." + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" }, - "defaultValue": {} - }, - "publicAccess": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Container", - "Blob", - "None" - ], + "defaultValue": [], "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + "description": "Optional. Queues to create." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." } }, - "roleAssignments": { + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/diagnosticSettingFullType" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The diagnostic settings of the service." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, + "name": "default", "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount::blobServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, + }, + "resources": { "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, - "container": { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", "properties": { - "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", - "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", - "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", - "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", - "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", - "metadata": "[parameters('metadata')]", - "publicAccess": "[parameters('publicAccess')]" + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" } }, - "container_roleAssignments": { + "queueServices_diagnosticSettings": { "copy": { - "name": "container_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "container" + "queueServices" ] }, - "container_immutabilityPolicy": { - "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -32647,17 +34462,14 @@ "storageAccountName": { "value": "[parameters('storageAccountName')]" }, - "containerName": { - "value": "[parameters('name')]" - }, - "immutabilityPeriodSinceCreationInDays": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" }, - "allowProtectedAppendWrites": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" }, - "allowProtectedAppendWritesAll": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -32665,15 +34477,93 @@ }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "15304742179563677019" + "templateHash": "12812824360066955039" }, - "name": "Storage Account Blob Container Immutability Policies", - "description": "This module deploys a Storage Account Blob Container Immutability Policy." + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { "storageAccountName": { @@ -32683,31 +34573,30 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "containerName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + "description": "Required. The name of the storage queue to deploy." } }, - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "defaultValue": 365, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "defaultValue": false, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair that represents queue metadata." + }, + "defaultValue": {} }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "defaultValue": false, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + "description": "Optional. Array of role assignments to create." } }, "enableTelemetry": { @@ -32718,12 +34607,42 @@ } } }, - "resources": [ - { + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -32739,66 +34658,89 @@ } } }, - { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", "properties": { - "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", - "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", - "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + "metadata": "[parameters('metadata')]" } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] } - ], + }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed immutability policy." + "description": "The name of the deployed queue." }, - "value": "default" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed immutability policy." + "description": "The resource ID of the deployed queue." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed immutability policy." + "description": "The resource group of the deployed queue." }, "value": "[resourceGroup().name]" } } } - }, - "dependsOn": [ - "container" - ] + } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed container." + "description": "The name of the deployed queue service." }, - "value": "[parameters('name')]" + "value": "[variables('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed container." + "description": "The resource ID of the deployed queue service." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed container." + "description": "The resource group of the deployed queue service." }, "value": "[resourceGroup().name]" } @@ -32806,601 +34748,735 @@ } }, "dependsOn": [ - "blobServices" + "storageAccount" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed blob service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - }, - "corsRules": { - "value": "[tryGet(parameters('fileServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17583198711200998285" }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + }, + "corsRules": { + "value": "[tryGet(parameters('tableServices'), 'corsRules')]" } }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10320403358700650147" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a file share." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" - }, - "description": "Optional. Protocol settings for file service." - }, - "defaultValue": {} - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" - }, - "description": "Optional. The service properties for soft delete." - }, - "defaultValue": { - "enabled": true, - "days": 7 - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } - }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11362260974696477885" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "fileServices" + "storageAccount" ] }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" - }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" - }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" - }, - "provisionedBandwidthMibps": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" - }, - "provisionedIops": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" } }, "template": { @@ -33411,711 +35487,1739 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "10353179772982843397" - }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share." + "templateHash": "13227497656004178962" + } }, "definitions": { - "roleAssignmentType": { + "secretSetOutputType": { "type": "object", "properties": { - "name": { + "secretResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "The resourceId of the exported secret." } }, - "roleDefinitionIdOrName": { + "secretUri": { "type": "string", "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "The secret URI of the exported secret." } }, - "principalId": { + "secretUriWithVersion": { "type": "string", "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "The secret URI with version of the exported secret." } - }, - "principalType": { + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Required. The name of the secret to set." } }, - "description": { + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_objectReplicationPolicies": { + "copy": { + "name": "storageAccount_objectReplicationPolicies", + "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "destinationAccountResourceId": { + "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" + }, + "enableMetrics": { + "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" + }, + "rules": { + "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1894366578172550759" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." } }, - "condition": { + "containerName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Required. The name of the source container." } }, - "conditionVersion": { + "destinationContainerName": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The filters for the object replication policy rule." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "The type of an object replication policy rule.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "policy/main.bicep" } } } }, "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { "type": "string", "nullable": true, - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + "description": "Optional. Name of the policy." } }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "enabledProtocols": { + "storageAccountName": { "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "maxLength": 24, "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Required. The name of the parent Storage Account." } }, - "rootSquash": { + "destinationAccountResourceId": { "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "minValue": 0, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." - } - }, - "provisionedIops": { - "type": "int", - "nullable": true, - "minValue": 0, - "maxValue": 102400, "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + "description": "Required. Resource ID of the destination storage account for replication." } }, - "enableTelemetry": { + "enableMetrics": { "type": "bool", - "defaultValue": true, + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Whether metrics are enabled for the object replication policy." } }, - "roleAssignments": { + "rules": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/objectReplicationPolicyRuleType" }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Required. Rules for the object replication policy." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", + "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", + "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", + "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" }, "resources": { - "storageAccount::fileService": { + "storageAccount": { "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", + "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + "name": "[parameters('storageAccountName')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "destinationPolicy": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", + "subscriptionId": "[variables('destAccountSubscription')]", + "resourceGroup": "[variables('destAccountResourceGroupName')]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('name'), 'default')]" + }, + "storageAccountName": { + "value": "[variables('destAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "value": "[parameters('rules')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" } } } } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]", - "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", - "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "fileShare_roleAssignments": { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, + "sourcePolicy": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "scope": { - "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" - }, "name": { - "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" - }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + "value": "[reference('destinationPolicy').outputs.policyId.value]" }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + "storageAccountName": { + "value": "[parameters('storageAccountName')]" }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" }, - "condition": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" }, - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "enableMetrics": { + "value": "[parameters('enableMetrics')]" }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + "rules": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('rules'))]", + "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } + ] } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, "parameters": { - "scope": { + "name": { "type": "string", "metadata": { - "description": "Required. The scope to deploy the role assignment to." + "description": "Required. Name of the policy." } }, - "name": { + "storageAccountName": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Required. The name of the role assignment." + "description": "Required. The name of the Storage Account on which to create the policy." } }, - "roleDefinitionId": { + "sourceStorageAccountResourceId": { "type": "string", "metadata": { - "description": "Required. The role definition Id to assign." + "description": "Required. Resource ID of the source storage account for replication." } }, - "principalId": { + "destinationAccountResourceId": { "type": "string", "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Required. Resource ID of the destination storage account for replication." } }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", + "enableMetrics": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Whether metrics are enabled for the object replication policy." } }, - "description": { - "type": "string", - "defaultValue": "", + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Required. Rules for the object replication policy." } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" }, - "condition": { + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" - } + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" }, - "conditionVersion": { + "objectReplicationPolicyId": { "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", "metadata": { - "description": "Optional. Version of the condition." - } + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" }, - "delegatedManagedIdentityResourceId": { + "policyId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[parameters('scope')]", - "name": "[parameters('name')]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "principalId": "[parameters('principalId')]", - "description": "[parameters('description')]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" } - ] + } } }, "dependsOn": [ - "fileShare" + "destinationPolicy" ] } }, - "outputs": { - "name": { + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.policyId.value]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2025-06-01', 'full').location]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." + }, + "value": "[reference('storageAccount').primaryEndpoints]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Storage Account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The primary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + }, + "secondaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The secondary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" + }, + "primaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" + }, + "secondaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", + "virtualNetwork" + ] + }, + "avmAiServices": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "projectName": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "projectDescription": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "existingFoundryProjectResourceId": { + "value": "[variables('existingProjectResourceId')]" + }, + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "sku": { + "value": "S0" + }, + "allowProjectManagement": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "kind": { + "value": "AIServices" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('azureAiServiceLocation')]" + } + }, + "customSubDomainName": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" + } + }, + "disableLocalAuth": { + "value": true + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "deployments": { + "value": [ + { + "name": "[parameters('gptModelName')]", + "model": { + "format": "OpenAI", + "name": "[parameters('gptModelName')]", + "version": "[parameters('gptModelVersion')]" + }, + "sku": { + "name": "[parameters('deploymentType')]", + "capacity": "[parameters('gptDeploymentCapacity')]" + }, + "raiPolicyName": "Microsoft.Default" + } + ] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18336251851332975005" + }, + "name": "Cognitive Services", + "description": "This module deploys a Cognitive Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "The name of the deployed file share." - }, - "value": "[parameters('name')]" + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceId": { + "memberName": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceGroupName": { + "privateIPAddress": { "type": "string", "metadata": { - "description": "The resource group of the deployed file share." - }, - "value": "[resourceGroup().name]" + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." } } }, - "dependsOn": [ - "fileServices", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", "metadata": { - "description": "The name of the deployed file share service." - }, - "value": "[parameters('name')]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "resourceId": { - "type": "string", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, "metadata": { - "description": "The resource ID of the deployed file share service." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "resourceGroupName": { - "type": "string", + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, "metadata": { - "description": "The resource group of the deployed file share service." + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/project.bicep" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_queueServices": { - "condition": "[not(empty(parameters('queueServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" - }, - "queues": { - "value": "[tryGet(parameters('queueServices'), 'queues')]" - }, - "corsRules": { - "value": "[tryGet(parameters('queueServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9644461291744477521" + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "name": "Storage Account Queue Services", - "description": "This module deploys a Storage Account Queue Service." - }, - "definitions": { - "corsRuleType": { + "diagnosticSettingFullType": { "type": "object", "properties": { - "allowedHeaders": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } }, + "nullable": true, "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "allowedMethods": { + "metricCategories": { "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" + "AzureDiagnostics", + "Dedicated" ], + "nullable": true, "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, + "workspaceResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "maxAgeInSeconds": { - "type": "int", + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "queueType": { + "lockType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the queue." + "description": "Optional. Specify the name of lock." } }, - "metadata": { - "type": "object", + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true + "description": "Optional. Specify the type of lock." + } }, - "roleAssignments": { + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a queue." + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "diagnosticSettingFullType": { + "privateEndpointSingleServiceType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "logCategoriesAndGroups": { + "customDnsConfigs": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" }, "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Optional. Custom DNS configurations." } }, - "metricCategories": { + "ipConfigurations": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" }, "nullable": true, "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." } }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." } }, - "workspaceResourceId": { + "customNetworkInterfaceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." } }, - "storageAccountResourceId": { - "type": "string", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Specify the type of lock." } }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. Array of role assignments to create." } }, - "eventHubName": { - "type": "string", + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." } }, - "marketplacePartnerResourceId": { - "type": "string", + "enableTelemetry": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, @@ -34190,138 +37294,428 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "storageAccountName": { + "name": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Required. The name of Cognitive Services account." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "" + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." } }, - "queues": { + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/queueType" + "$ref": "#/definitions/diagnosticSettingFullType" }, - "defaultValue": [], + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, "metadata": { - "description": "Optional. Queues to create." + "description": "Optional. A collection of rules governing the accessibility from specific network locations." } }, - "corsRules": { + "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/corsRuleType" + "$ref": "#/definitions/privateEndpointSingleServiceType" }, "nullable": true, "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, - "diagnosticSettings": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "allowProjectManagement": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable project management feature for AI Foundry." } } }, "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", + "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" }, "resources": { - "storageAccount": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" }, - "queueServices": { - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "queueServices_diagnosticSettings": { - "copy": { - "name": "queueServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2025-01-31-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "cognitiveServiceNew": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "allowProjectManagement": "[parameters('allowProjectManagement')]", + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" }, "dependsOn": [ - "queueServices" + "cMKKeyVault", + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" ] }, - "queueServices_queues": { - "copy": { - "name": "queueServices_queues", - "count": "[length(coalesce(parameters('queues'), createArray()))]" - }, + "cognitiveServiceExisting": { + "condition": "[variables('useExistingService')]", + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "cognitive_service_dependencies": { + "condition": "[not(variables('useExistingService'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" }, "name": { - "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + "value": "[parameters('name')]" }, - "metadata": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[parameters('roleAssignments')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -34331,736 +37725,697 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "12812824360066955039" - }, - "name": "Storage Account Queues", - "description": "This module deploys a Storage Account Queue." + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } }, "definitions": { - "roleAssignmentType": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." } }, - "roleDefinitionIdOrName": { + "raiPolicyName": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of RAI policy." } }, - "principalId": { + "versionUpgradeOption": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The version upgrade option." } - }, - "principalType": { + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Type of the endpoint." } }, - "description": { + "endpoint": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "The endpoint URI." } - }, - "condition": { + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." } }, - "conditionVersion": { + "accessKey1Name": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The name for the accessKey1 secret to create." } }, - "delegatedManagedIdentityResourceId": { + "accessKey2Name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The name for the accessKey2 secret to create." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the storage queue to deploy." + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." } }, - "metadata": { + "_1.privateEndpointCustomDnsConfigType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } }, - "description": "Optional. A name-value pair that represents queue metadata." - }, - "defaultValue": {} - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "storageAccount::queueServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "queue": { - "type": "Microsoft.Storage/storageAccounts/queueServices/queues", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "_1.secretSetOutputType": { + "type": "object", "properties": { - "metadata": "[parameters('metadata')]" + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "queue_roleAssignments": { - "copy": { - "name": "queue_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "aiProjectOutputType": { + "type": "object", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "queue" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed queue." + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed queue." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed queue." - }, - "value": "[resourceGroup().name]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed queue service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed queue service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed queue service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_tableServices": { - "condition": "[not(empty(parameters('tableServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" - }, - "tables": { - "value": "[tryGet(parameters('tableServices'), 'tables')]" - }, - "corsRules": { - "value": "[tryGet(parameters('tableServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "10320403358700650147" - }, - "name": "Storage Account Table Services", - "description": "This module deploys a Storage Account Table Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "tableServices": { - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" - } - }, - "tableServices_diagnosticSettings": { - "copy": { - "name": "tableServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "tableServices" - ] - }, - "tableServices_tables": { - "copy": { - "name": "tableServices_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "11362260974696477885" }, - "name": "Storage Account Table", - "description": "This module deploys a Storage Account Table." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -35130,19 +38485,108 @@ } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, "roleAssignments": { @@ -35155,17 +38599,33 @@ "description": "Optional. Array of role assignments to create." } }, - "name": { + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { "type": "string", "metadata": { - "description": "Required. Name of the table." + "description": "Optional: Name for the project which needs to be created." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "projectDescription": { + "type": "string", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" } } }, @@ -35178,66 +38638,121 @@ } ], "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "enableReferencedModulesTelemetry": false }, "resources": { - "storageAccount::tableServices": { + "cognitiveService": { "existing": true, - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } - } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "table": { - "type": "Microsoft.Storage/storageAccounts/tableServices/tables", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" - }, - "table_roleAssignments": { + "cognitiveService_roleAssignments": { "copy": { - "name": "table_roleAssignments", + "name": "cognitiveService_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -35246,3022 +38761,3366 @@ "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "table" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed table." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed table." - }, - "value": "[resourceGroup().name]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed table service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed table service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed table service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13227497656004178962" - } - }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_objectReplicationPolicies": { - "copy": { - "name": "storageAccount_objectReplicationPolicies", - "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "destinationAccountResourceId": { - "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" - }, - "enableMetrics": { - "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" - }, - "rules": { - "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1894366578172550759" - }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } - }, - "minCreationTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "description": "The type of an object replication policy rule.", - "__bicep_imported_from!": { - "sourceTemplate": "policy/main.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the parent Storage Account." - } - }, - "destinationAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." - } - } - }, - "variables": { - "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", - "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", - "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", - "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "destinationPolicy": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", - "subscriptionId": "[variables('destAccountSubscription')]", - "resourceGroup": "[variables('destAccountResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('name'), 'default')]" - }, - "storageAccountName": { - "value": "[variables('destAccountName')]" - }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" - }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" - }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" - }, - "rules": { - "value": "[parameters('rules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14995722372031126283" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, - "destinationContainerName": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { "type": "array", "items": { "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "minCreationTime": { + "customNetworkInterfaceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy rule." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." - } - }, - "sourceStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the source storage account for replication." - } - }, - "destinationAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" - }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').policyId]" - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true - }, - "description": "Rules created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').rules]" - } - } - } - } - }, - "sourcePolicy": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[reference('destinationPolicy').outputs.policyId.value]" - }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" - }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" - }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" - }, - "rules": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('rules'))]", - "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14995722372031126283" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" } }, - "destinationContainerName": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/secretToSetType" }, - "nullable": true, "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." + "description": "Required. The secrets to set in the Key Vault." } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" }, - "minCreationTime": { - "type": "string", - "nullable": true, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } } } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." } } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy rule." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." - } - }, - "sourceStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the source storage account for replication." - } - }, - "destinationAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" - } - } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" + "expressionEvaluationOptions": { + "scope": "inner" }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').policyId]" - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } }, - "description": "Rules created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').rules]" - } - } - } - }, - "dependsOn": [ - "destinationPolicy" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.policyId.value]" - } - } - } - }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2025-06-01', 'full').location]" - }, - "serviceEndpoints": { - "type": "object", - "metadata": { - "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." - }, - "value": "[reference('storageAccount').primaryEndpoints]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the Storage Account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "primaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The primary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - }, - "secondaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The secondary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" - }, - "primaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" - }, - "secondaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", - "virtualNetwork" - ] - }, - "avmAiServices": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "projectName": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "projectDescription": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "existingFoundryProjectResourceId": { - "value": "[variables('existingProjectResourceId')]" - }, - "location": { - "value": "[parameters('azureAiServiceLocation')]" - }, - "sku": { - "value": "S0" - }, - "allowProjectManagement": { - "value": true - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "kind": { - "value": "AIServices" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('azureAiServiceLocation')]" - } - }, - "customSubDomainName": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" - } - }, - "disableLocalAuth": { - "value": true - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "deployments": { - "value": [ - { - "name": "[parameters('gptModelName')]", - "model": { - "format": "OpenAI", - "name": "[parameters('gptModelName')]", - "version": "[parameters('gptModelVersion')]" - }, - "sku": { - "name": "[parameters('deploymentType')]", - "capacity": "[parameters('gptDeploymentCapacity')]" - }, - "raiPolicyName": "Microsoft.Default" - } - ] - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "18336251851332975005" - }, - "name": "Cognitive Services", - "description": "This module deploys a Cognitive Service." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/project.bicep" - } - } - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } + }, + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "dependsOn": [ + "cognitiveServiceNew" + ] }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "projectName": { - "type": "string", - "metadata": { - "description": "Optional: Name for the project which needs to be created." - } - }, - "projectDescription": { - "type": "string", - "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "" - }, - "kind": { - "type": "string", - "allowedValues": [ - "AIServices", - "AnomalyDetector", - "CognitiveServices", - "ComputerVision", - "ContentModerator", - "ContentSafety", - "ConversationalLanguageUnderstanding", - "CustomVision.Prediction", - "CustomVision.Training", - "Face", - "FormRecognizer", - "HealthInsights", - "ImmersiveReader", - "Internal.AllInOne", - "LUIS", - "LUIS.Authoring", - "LanguageAuthoring", - "MetricsAdvisor", - "OpenAI", - "Personalizer", - "QnAMaker.v2", - "SpeechServices", - "TextAnalytics", - "TextTranslation" - ], - "metadata": { - "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "sku": { - "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "customSubDomainName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." - } - }, - "networkAcls": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A collection of rules governing the accessibility from specific network locations." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "allowedFqdnList": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of allowed FQDN." - } - }, - "apiProperties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The API properties for special APIs." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "dynamicThrottlingEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag to enable dynamic throttling." - } - }, - "migrationToken": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. Resource migration token." - } - }, - "restore": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." - } - }, - "restrictOutboundNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Restrict outbound network access." - } - }, - "userOwnedStorage": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The storage accounts for this resource." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "allowProjectManagement": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable project management feature for AI Foundry." - } - } - }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", - "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2025-01-31-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "cognitiveServiceNew": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]", - "kind": "[parameters('kind')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "properties": { - "allowProjectManagement": "[parameters('allowProjectManagement')]", - "customSubDomainName": "[parameters('customSubDomainName')]", - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", - "allowedFqdnList": "[parameters('allowedFqdnList')]", - "apiProperties": "[parameters('apiProperties')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", - "migrationToken": "[parameters('migrationToken')]", - "restore": "[parameters('restore')]", - "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", - "userOwnedStorage": "[parameters('userOwnedStorage')]", - "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "cognitiveServiceExisting": { - "condition": "[variables('useExistingService')]", - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", - "name": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "cognitive_service_dependencies": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "deployments": { - "value": "[parameters('deployments')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" - }, - "sku": { - "value": "[parameters('sku')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8883353547455396972" - } - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", + "existing_cognitive_service_dependencies": { + "condition": "[variables('useExistingService')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, - "groupId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } } } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } } }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "memberName": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } } }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." } } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services account." }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" + }, + "resourceId": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The resource ID of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } + "subscriptionId": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } + "endpoint": { + "type": "string", + "metadata": { + "description": "The service endpoint of the cognitive services account." }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" + }, + "endpoints": { + "$ref": "#/definitions/endpointType", "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" + }, + "location": { + "type": "string", "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } - } + "description": "The location the resource was deployed into." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "description": "The private endpoints of the congitive services account." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "logAnalyticsWorkspace" + ] + }, + "cognitiveServicePrivateEndpoint": { + "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": { + "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", + "properties": { + "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", + "groupIds": [ + "account" + ] } } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "name": "ai-services-dns-zone-cognitiveservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } + { + "name": "ai-services-dns-zone-openai", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + { + "name": "ai-services-dns-zone-aiservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-contentunderstanding", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" } - } + ] + } + }, + "subnetResourceId": { + "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" }, - "privateEndpointSingleServiceType": { + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + "description": "Optional. The name of the Private DNS Zone Group." } }, - "applicationSecurityGroupResourceIds": { + "privateDnsZoneGroupConfigs": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/privateDnsZoneGroupConfigType" }, - "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." } - }, - "customNetworkInterfaceName": { + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + "description": "Optional. Specify the name of lock." } }, - "lock": { - "$ref": "#/definitions/lockType", + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { "description": "Optional. Specify the type of lock." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, + "notes": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Specify the notes of the lock." } - }, - "tags": { - "type": "object", + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + "description": "Optional. The name of the private DNS zone group config." } }, - "enableTelemetry": { - "type": "bool", - "nullable": true, + "privateDnsZoneResourceId": { + "type": "string", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. The resource id of the private DNS zone." } } }, "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "description": "The type of a private DNS zone group configuration.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "private-dns-zone-group/main.bicep" } } }, @@ -38339,96 +42198,70 @@ "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account." + "description": "Required. Name of the private endpoint resource to create." } }, - "sku": { + "subnetResourceId": { "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "tags": { - "type": "object", + "customNetworkInterfaceName": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "deployments": { + "ipConfigurations": { "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." }, - "nullable": true, + "nullable": true + }, + "ipVersionType": { + "type": "string", "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "nullable": true, "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. Location for all Resources." } }, "lock": { @@ -38448,33 +42281,51 @@ "description": "Optional. Array of role assignments to create." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." }, - "nullable": true, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", "metadata": { - "description": "Optional. The diagnostic settings of the service." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true }, - "projectName": { - "type": "string", + "manualPrivateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Optional: Name for the project which needs to be created." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true }, - "projectDescription": { - "type": "string", + "privateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Optional: Description for the project which needs to be created." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + "description": "Optional. Enable/Disable usage telemetry for module." } } }, @@ -38487,121 +42338,89 @@ } ], "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } }, "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" - }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" - }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" - }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { "copy": [ { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" } } ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" } }, - "cognitiveService_roleAssignments": { + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { "copy": { - "name": "cognitiveService_roleAssignments", + "name": "privateEndpoint_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -38610,18 +42429,16 @@ "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } - }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -38629,42 +42446,13 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "privateEndpointName": { + "value": "[parameters('name')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" } }, "template": { @@ -38675,74 +42463,12 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "18436885663402767850" + "templateHash": "9935179114830442414" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." }, "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, "privateDnsZoneGroupConfigType": { "type": "object", "properties": { @@ -38757,547 +42483,1096 @@ "type": "string", "metadata": { "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." } } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { + "privateEndpointName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "applicationSecurityGroupResourceIds": { + "privateDnsZoneConfigs": { "type": "array", "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + "$ref": "#/definitions/privateDnsZoneGroupConfigType" }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, + "minLength": 1, + "maxLength": 5, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." } }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "defaultValue": "default", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "Optional. The name of the private DNS zone group." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, "privateEndpoint": { + "existing": true, "type": "Microsoft.Network/privateEndpoints", "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { "copy": [ { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } } } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" + ] } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[parameters('name')]" }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "avmAiServices", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", + "virtualNetwork" + ] + }, + "avmContainerAppEnv": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('cae-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", + "workloadProfiles": { + "value": [ + { + "name": "Consumption", + "workloadProfileType": "Consumption" + } + ] + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "platformReservedCidr": { + "value": "172.17.17.0/24" + }, + "platformReservedDnsIP": { + "value": "172.17.17.17" + }, + "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", + "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11924518395502120940" + }, + "name": "App ManagedEnvironments", + "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." + }, + "definitions": { + "certificateType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the certificate." + } + }, + "certificateType": { + "type": "string", + "allowedValues": [ + "ImagePullTrustedCA", + "ServerSSLCertificate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location for the resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a certificate." + } + }, + "storageType": { + "type": "object", + "properties": { + "accessMode": { + "type": "string", + "allowedValues": [ + "ReadOnly", + "ReadWrite" + ], + "metadata": { + "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. File share name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the storage." + } + }, + "appLogsConfigurationType": { + "type": "object", + "discriminator": { + "propertyName": "destination", + "mapping": { + "azure-monitor": { + "$ref": "#/definitions/appLogsConfigurationMonitorType" + }, + "log-analytics": { + "$ref": "#/definitions/appLogsConfigurationLawType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the App Logs Configuration." + } + }, + "appLogsConfigurationMonitorType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "azure-monitor" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using azure-monitor." + } + }, + "appLogsConfigurationLawType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "log-analytics" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Existing Log Analytics Workspace resource ID." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using log-analytics." + } + }, + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } + }, + "metadata": { + "description": "The type for the certificate's key vault properties.", + "__bicep_imported_from!": { + "sourceTemplate": "certificate/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string." + } + }, + "daprConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" + }, + "description": "Optional. The configuration of Dapr component." + }, + "nullable": true + }, + "ingressConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" + }, + "description": "Optional. Ingress configuration for the Managed Environment." + }, + "nullable": true + }, + "kedaConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" + }, + "description": "Optional. The configuration of Keda component." + }, + "nullable": true + }, + "peerAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" + }, + "description": "Optional. Peer authentication settings for the Managed Environment." + }, + "nullable": true + }, + "daprAIConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." + } + }, + "daprAIInstrumentationKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." + } + }, + "dockerBridgeCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "infrastructureSubnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "internal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedDnsIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "peerTrafficEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not to encrypt peer traffic." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether to allow or block all public traffic." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not this Managed Environment is zone-redundant." + } + }, + "certificatePassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Password of the certificate used by the custom domain." + } + }, + "certificateValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Certificate to use for the custom domain. PFX or PEM." + } + }, + "dnsSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. DNS suffix for the environment domain." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "openTelemetryConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" + }, + "description": "Optional. Open Telemetry configuration." + }, + "nullable": true + }, + "workloadProfiles": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" + }, + "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." + }, + "nullable": true + }, + "infrastructureResourceGroupName": { + "type": "string", + "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", + "metadata": { + "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "storages": { + "type": "array", + "items": { + "$ref": "#/definitions/storageType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of storages to mount on the environment." + } + }, + "certificate": { + "$ref": "#/definitions/certificateType", + "nullable": true, + "metadata": { + "description": "Optional. A Managed Environment Certificate." + } + }, + "appLogsConfiguration": { + "$ref": "#/definitions/appLogsConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The AppLogsConfiguration for the Managed Environment." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-11-01", + "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } + } + } + } + }, + "logAnalyticsWorkspace": { + "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-02-01", + "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" + }, + "managedEnvironment": { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "appInsightsConfiguration": { + "connectionString": "[parameters('appInsightsConnectionString')]" + }, + "daprConfiguration": "[parameters('daprConfiguration')]", + "ingressConfiguration": "[parameters('ingressConfiguration')]", + "kedaConfiguration": "[parameters('kedaConfiguration')]", + "peerAuthentication": "[parameters('peerAuthentication')]", + "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", + "daprAIConnectionString": "[parameters('daprAIConnectionString')]", + "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", + "customDomainConfiguration": { + "certificatePassword": "[parameters('certificatePassword')]", + "certificateValue": "[parameters('certificateValue')]", + "dnsSuffix": "[parameters('dnsSuffix')]", + "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" + }, + "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", + "peerTrafficConfiguration": { + "encryption": { + "enabled": "[parameters('peerTrafficEncryption')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "vnetConfiguration": { + "internal": "[parameters('internal')]", + "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", + "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", + "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", + "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" + }, + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]", + "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "managedEnvironment_roleAssignments": { + "copy": { + "name": "managedEnvironment_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_storage": { + "copy": { + "name": "managedEnvironment_storage", + "count": "[length(coalesce(parameters('storages'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" }, - "outputs": { - "resourceGroupName": { + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "kind": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + }, + "accessMode": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + }, + "storageAccountName": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "945327737463253676" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "parameters": { + "name": { "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" + "description": "Required. The name of the file share." + } }, - "resourceId": { + "managedEnvironmentName": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } }, - "name": { + "accessMode": { "type": "string", "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" + "description": "Required. The access mode for the storage." + } }, - "location": { + "kind": { "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } }, - "customDnsConfigs": { - "type": "array", + "storageAccountName": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." + "description": "Required. Storage account name." + } + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "storage": { + "type": "Microsoft.App/managedEnvironments/storages", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "properties": { + "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", + "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the file share." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[parameters('name')]" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "resourceId": { + "type": "string", "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The resource ID of the file share." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" }, - "groupId": { + "resourceGroupName": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The resource group the file share was deployed into." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[resourceGroup().name]" } } } - } + }, + "dependsOn": [ + "managedEnvironment" + ] }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "managedEnvironment_certificate": { + "condition": "[not(empty(parameters('certificate')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + "name": { + "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "certificateKeyVaultProperties": { + "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" + }, + "certificateType": { + "value": "[tryGet(parameters('certificate'), 'certificateType')]" + }, + "certificateValue": { + "value": "[tryGet(parameters('certificate'), 'certificateValue')]" + }, + "certificatePassword": { + "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" + }, + "location": { + "value": "[tryGet(parameters('certificate'), 'location')]" + }, + "tags": { + "value": "[tryGet(parameters('certificate'), 'tags')]" } }, "template": { @@ -39308,127 +43583,563 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "13560950051680758953" - } + "templateHash": "574133184207535827" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." }, "definitions": { - "secretSetOutputType": { + "certificateKeyVaultPropertiesType": { "type": "object", "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { + "identityResourceId": { "type": "string", "metadata": { - "description": "The secret URI of the exported secret." + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." } }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { + "keyVaultUrl": { "type": "string", "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." } } }, "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for the certificate's key vault properties." } } }, "parameters": { - "keyVaultName": { + "name": { "type": "string", "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." + "description": "Required. Name of the Container Apps Managed Environment Certificate." } }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, + "managedEnvironmentName": { + "type": "string", "metadata": { - "description": "Required. The secrets to set in the Key Vault." + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference to the certificate to use for the custom domain." + } + }, + "certificateType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ServerSSLCertificate", + "ImagePullTrustedCA" + ], + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true } }, "resources": { - "keyVault": { + "managedEnvironment": { "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "managedEnvironmentCertificate": { + "type": "Microsoft.App/managedEnvironments/certificates", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", + "certificateType": "[parameters('certificateType')]", + "password": "[parameters('certificatePassword')]", + "value": "[parameters('certificateValue')]" + }, + "tags": "[parameters('tags')]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } + "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the certificate was deployed into." + }, + "value": "[resourceGroup().name]" } + } + } + }, + "dependsOn": [ + "managedEnvironment" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Managed Environment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Managed Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Managed Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('managedEnvironment').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The IP address of the Managed Environment." + }, + "value": "[reference('managedEnvironment').staticIp]" + }, + "domainVerificationId": { + "type": "string", + "metadata": { + "description": "The domain verification id for custom domains." + }, + "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "virtualNetwork" + ] + }, + "avmContainerRegistryReader": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } } } }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -39436,196 +44147,158 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" }, - "aiServicesName": { + "userAssignedIdentityName": { "value": "[parameters('name')]" }, - "location": { - "value": "[parameters('location')]" + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" }, - "tags": { - "value": "[parameters('tags')]" + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } - } + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." }, "parameters": { - "name": { + "userAssignedIdentityName": { "type": "string", "metadata": { - "description": "Required. Name of the AI Services project." + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." } }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The location of the Project resource." + "description": "Required. The name of the secret." } }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", + "audiences": { + "type": "array", "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." } }, - "aiServicesName": { + "issuer": { "type": "string", "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." } }, - "azureExistingAIProjectResourceId": { + "subject": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." } } }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" - }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" } } - }, + ], "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", + "name": { + "type": "string", "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." + "description": "The name of the federated identity credential." }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" } } } - } + }, + "dependsOn": [ + "userAssignedIdentity" + ] } }, "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", + "name": { + "type": "string", "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + "description": "The name of the user assigned identity." }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + "value": "[parameters('name')]" }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", "metadata": { - "description": "The private endpoints of the congitive services account." + "description": "The principal ID (object ID) of the user assigned identity." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } + "value": "[reference('userAssignedIdentity').principalId]" }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" } } } - }, - "dependsOn": [ - "cognitiveServiceNew" - ] + } }, - "existing_cognitive_service_dependencies": { - "condition": "[variables('useExistingService')]", + "avmContainerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -39633,40 +44306,87 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[variables('existingCognitiveServiceDetails')[8]]" + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" }, - "projectName": { - "value": "[parameters('projectName')]" + "location": { + "value": "[parameters('location')]" }, - "projectDescription": { - "value": "[parameters('projectDescription')]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('existingFoundryProjectResourceId')]" + "workloadProfileName": { + "value": "Consumption" }, - "location": { - "value": "[parameters('location')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "deployments": { - "value": "[parameters('deployments')]" + "registries": { + "value": null }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } }, - "lock": { - "value": "[parameters('lock')]" + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" + "activeRevisionsMode": { + "value": "Single" }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" + "ingressExternal": { + "value": false }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" + "disableIngress": { + "value": true }, - "sku": { - "value": "[parameters('sku')]" + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } }, "tags": { "value": "[parameters('tags')]" @@ -39680,433 +44400,556 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "8883353547455396972" - } + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." }, "definitions": { - "privateEndpointOutputType": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "Required. The name of the service." } }, - "resourceId": { + "serviceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." } }, - "groupId": { + "secretRef": { "type": "string", "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." } }, - "customDnsConfigs": { + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { "type": "array", "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" }, + "nullable": true, "metadata": { - "description": "The custom DNS configurations of the private endpoint." + "description": "Optional. Specifies the content for the access-control-allow-origins header." } }, - "networkInterfaceResourceIds": { + "exposeHeaders": { "type": "array", "items": { "type": "string" }, + "nullable": true, "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." } } }, "metadata": { "__bicep_export!": true, - "description": "The type for the private endpoint output." + "description": "The type for a CORS policy." } }, - "deploymentType": { + "containerAppProbeHttpGetType": { "type": "object", "properties": { - "name": { + "host": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." + "description": "Optional. Host name to connect to. Defaults to the pod IP." } }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" }, + "nullable": true, "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." + "description": "Optional. HTTP headers to set in the request." } }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, + "path": { + "type": "string", "metadata": { - "description": "Optional. The resource model definition representing SKU." + "description": "Required. Path to access on the HTTP server." } }, - "raiPolicyName": { - "type": "string", - "nullable": true, + "port": { + "type": "int", "metadata": { - "description": "Optional. The name of RAI policy." + "description": "Required. Name or number of the port to access on the container." } }, - "versionUpgradeOption": { + "scheme": { "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], "nullable": true, "metadata": { - "description": "Optional. The version upgrade option." + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." + "description": "The type for a container app probe HTTP GET." } }, - "endpointType": { + "containerAppProbeHttpGetHeadersItemType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Type of the endpoint." + "description": "Required. Name of the header." } }, - "endpoint": { + "value": { "type": "string", - "nullable": true, "metadata": { - "description": "The endpoint URI." + "description": "Required. Value of the header." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." + "description": "The type for a container app probe HTTP GET header." } }, - "secretsExportConfigurationType": { + "containerAppProbeTcpSocketType": { "type": "object", "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { + "host": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." + "description": "Optional. Host name to connect to, defaults to the pod IP." } }, - "accessKey2Name": { - "type": "string", - "nullable": true, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." + "description": "The type for a container app probe TCP socket." } }, - "_1.privateEndpointCustomDnsConfigType": { + "scaleType": { "type": "object", "properties": { - "fqdn": { - "type": "string", + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. The cooldown period in seconds." } }, - "ipAddresses": { + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/scaleRuleType" }, + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. The scaling rules." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The scale settings for the Container App." } }, - "_1.privateEndpointIpConfigurationType": { + "scaleRuleType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. The name of the scaling rule." } }, - "properties": { + "custom": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The scaling rules for the Container App." } }, - "_1.privateEndpointPrivateDnsZoneGroupType": { + "volumeMountType": { "type": "object", "properties": { - "name": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, + "volumeName": { + "type": "string", "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + "description": "Required. This must match the Name of a Volume." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The type for a volume mount." } }, - "_1.secretSetOutputType": { + "secretType": { "type": "object", "properties": { - "secretResourceId": { + "identity": { "type": "string", + "nullable": true, "metadata": { - "description": "The resourceId of the exported secret." + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." } }, - "secretUri": { + "keyVaultUrl": { "type": "string", + "nullable": true, "metadata": { - "description": "The secret URI of the exported secret." + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." } }, - "secretUriWithVersion": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "The secret URI with version of the exported secret." + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." } } }, "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for a secret." } }, - "aiProjectOutputType": { + "authConfigType": { "type": "object", "properties": { - "name": { - "type": "string", + "encryptionSettings": { + "type": "object", "metadata": { - "description": "Required. Name of the AI project." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "resourceId": { - "type": "string", + "globalValidation": { + "type": "object", "metadata": { - "description": "Required. Resource ID of the AI project." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true }, - "apiEndpoint": { - "type": "string", + "httpSettings": { + "type": "object", "metadata": { - "description": "Required. API endpoint for the AI project." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true } }, "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." } }, - "diagnosticSettingFullType": { + "diagnosticSettingMetricsOnlyType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Optional. The name of diagnostic setting." } }, "metricCategories": { @@ -40182,9 +45025,9 @@ } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -40221,152 +45064,35 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "privateEndpointSingleServiceType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { + "systemAssigned": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "applicationSecurityGroupResourceIds": { + "userAssignedResourceIds": { "type": "array", "items": { "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -40441,23 +45167,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -40466,74 +45176,161 @@ "name": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account." + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." } }, - "sku": { + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { "type": "string", - "defaultValue": "S0", + "defaultValue": "none", "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" + "none", + "sticky" ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Optional. Bool indicating if the Container App should enable session affinity." } }, - "location": { + "ingressTransport": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Ingress transport protocol." } }, - "tags": { + "service": { "type": "object", - "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." } }, - "deployments": { + "additionalPortMappings": { "type": "array", "items": { - "$ref": "#/definitions/deploymentType" + "$ref": "#/definitions/ingressPortMappingType" }, "nullable": true, "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." + "description": "Optional. Settings to expose additional ports on container app." } }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } }, - "privateEndpoints": { + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" + "$ref": "#/definitions/serviceBindingType" }, "nullable": true, "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." } }, "lock": { @@ -40543,529 +45340,457 @@ "description": "Optional. The lock settings of the service." } }, - "roleAssignments": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The managed identity definition for this resource." } }, - "diagnosticSettings": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." } }, - "projectName": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional: Name for the project which needs to be created." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "projectDescription": { - "type": "string", + "customDomains": { + "type": "array", "metadata": { - "description": "Optional: Description for the project which needs to be created." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." } }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + "description": "Optional. Max inactive revisions a Container App can have." } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." } - ], - "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." } }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." } }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." } }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" }, - "customNetworkInterfaceName": { + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." } }, - "ipConfigurations": { - "type": "array", + "encryptionSettings": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "ipVersionType": { - "type": "string", + "globalValidation": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } + "nullable": true }, - "tags": { + "httpSettings": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "customDnsConfigs": { - "type": "array", + "identityProviders": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" }, - "description": "Optional. Custom DNS configurations." + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "manualPrivateLinkServiceConnections": { - "type": "array", + "login": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "privateLinkServiceConnections": { - "type": "array", + "platform": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." }, "nullable": true }, @@ -41077,33 +45802,12 @@ } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -41119,2158 +45823,1811 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "current" }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceGroup().name]" } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_API": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" } } } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." } }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "serviceBindingType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13560950051680758953" - } + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." - } + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "lockType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services project." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. The location of the Project resource." - } - }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } - }, - "aiServicesName": { - "type": "string", - "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" - } - } - }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" - }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" - } - } - }, - "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." - }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } - } - } - } + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." } - } - }, - "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + "nullable": true }, - "privateEndpoints": { + "secrets": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "$ref": "#/definitions/secretType" }, + "nullable": true, "metadata": { - "description": "The private endpoints of the congitive services account." + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." } }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The service endpoint of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" - }, - "endpoints": { - "$ref": "#/definitions/endpointType", - "metadata": { - "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "logAnalyticsWorkspace" - ] - }, - "cognitiveServicePrivateEndpoint": { - "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "customNetworkInterfaceName": { - "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" - }, - "privateLinkServiceConnections": { - "value": [ - { - "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", - "properties": { - "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", - "groupIds": [ - "account" - ] - } - } - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDnsZoneGroupConfigs": [ - { - "name": "ai-services-dns-zone-cognitiveservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-openai", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-aiservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-contentunderstanding", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" - } - ] - } - }, - "subnetResourceId": { - "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "enableReferencedModulesTelemetry": false }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } } }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } + "dependsOn": [ + "containerApp" + ] }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "avmAiServices", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", - "virtualNetwork" - ] - }, - "avmContainerAppEnv": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('cae-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", - "workloadProfiles": { - "value": [ - { - "name": "Consumption", - "workloadProfileType": "Consumption" - } - ] - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "publicNetworkAccess": { - "value": "Enabled" - }, - "platformReservedCidr": { - "value": "172.17.17.0/24" - }, - "platformReservedDnsIP": { - "value": "172.17.17.17" - }, - "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", - "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.containersSubnetResourceId.value), createObject('value', null()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "11924518395502120940" - }, - "name": "App ManagedEnvironments", - "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." - }, - "definitions": { - "certificateType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the certificate." - } - }, - "certificateType": { - "type": "string", - "allowedValues": [ - "ImagePullTrustedCA", - "ServerSSLCertificate" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the certificate." - } - }, - "certificateValue": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." - } - }, - "certificatePassword": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The password of the certificate." - } - }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", - "nullable": true, - "metadata": { - "description": "Optional. A key vault reference." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location for the resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a certificate." - } - }, - "storageType": { - "type": "object", - "properties": { - "accessMode": { - "type": "string", - "allowedValues": [ - "ReadOnly", - "ReadWrite" - ], - "metadata": { - "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Required. Storage account name." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. File share name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the storage." - } - }, - "appLogsConfigurationType": { - "type": "object", - "discriminator": { - "propertyName": "destination", - "mapping": { - "azure-monitor": { - "$ref": "#/definitions/appLogsConfigurationMonitorType" - }, - "log-analytics": { - "$ref": "#/definitions/appLogsConfigurationLawType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the App Logs Configuration." - } - }, - "appLogsConfigurationMonitorType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "azure-monitor" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using azure-monitor." - } - }, - "appLogsConfigurationLawType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "log-analytics" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - }, - "logAnalyticsWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Existing Log Analytics Workspace resource ID." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using log-analytics." - } - }, - "certificateKeyVaultPropertiesType": { - "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } - }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } - }, - "metadata": { - "description": "The type for the certificate's key vault properties.", - "__bicep_imported_from!": { - "sourceTemplate": "certificate/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container Apps Managed Environment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "appInsightsConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string." - } - }, - "daprConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" - }, - "description": "Optional. The configuration of Dapr component." - }, - "nullable": true - }, - "ingressConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" - }, - "description": "Optional. Ingress configuration for the Managed Environment." - }, - "nullable": true - }, - "kedaConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" - }, - "description": "Optional. The configuration of Keda component." - }, - "nullable": true - }, - "peerAuthentication": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" - }, - "description": "Optional. Peer authentication settings for the Managed Environment." - }, - "nullable": true - }, - "daprAIConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." - } - }, - "daprAIInstrumentationKey": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." - } - }, - "dockerBridgeCidr": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "infrastructureSubnetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "internal": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "platformReservedCidr": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "platformReservedDnsIP": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "peerTrafficEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not to encrypt peer traffic." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether to allow or block all public traffic." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not this Managed Environment is zone-redundant." - } - }, - "certificatePassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Password of the certificate used by the custom domain." - } - }, - "certificateValue": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. Certificate to use for the custom domain. PFX or PEM." - } - }, - "dnsSuffix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. DNS suffix for the environment domain." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "openTelemetryConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" - }, - "description": "Optional. Open Telemetry configuration." - }, - "nullable": true - }, - "workloadProfiles": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" - }, - "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." - }, - "nullable": true - }, - "infrastructureResourceGroupName": { - "type": "string", - "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", - "metadata": { - "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "storages": { - "type": "array", - "items": { - "$ref": "#/definitions/storageType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of storages to mount on the environment." - } - }, - "certificate": { - "$ref": "#/definitions/certificateType", - "nullable": true, - "metadata": { - "description": "Optional. A Managed Environment Certificate." - } - }, - "appLogsConfiguration": { - "$ref": "#/definitions/appLogsConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The AppLogsConfiguration for the Managed Environment." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-11-01", - "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } - } - }, - "logAnalyticsWorkspace": { - "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", - "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" - }, - "managedEnvironment": { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "appInsightsConfiguration": { - "connectionString": "[parameters('appInsightsConnectionString')]" - }, - "daprConfiguration": "[parameters('daprConfiguration')]", - "ingressConfiguration": "[parameters('ingressConfiguration')]", - "kedaConfiguration": "[parameters('kedaConfiguration')]", - "peerAuthentication": "[parameters('peerAuthentication')]", - "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", - "daprAIConnectionString": "[parameters('daprAIConnectionString')]", - "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", - "customDomainConfiguration": { - "certificatePassword": "[parameters('certificatePassword')]", - "certificateValue": "[parameters('certificateValue')]", - "dnsSuffix": "[parameters('dnsSuffix')]", - "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" - }, - "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", - "peerTrafficConfiguration": { - "encryption": { - "enabled": "[parameters('peerTrafficEncryption')]" - } - }, - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "vnetConfiguration": { - "internal": "[parameters('internal')]", - "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", - "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", - "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", - "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" - }, - "workloadProfiles": "[parameters('workloadProfiles')]", - "zoneRedundant": "[parameters('zoneRedundant')]", - "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "managedEnvironment_roleAssignments": { - "copy": { - "name": "managedEnvironment_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "managedEnvironment" + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] }, - "managedEnvironment_storage": { - "copy": { - "name": "managedEnvironment_storage", - "count": "[length(coalesce(parameters('storages'), createArray()))]" - }, + "avmContainerApp_Web": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -43278,19 +47635,110 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" + "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" }, - "managedEnvironmentName": { - "value": "[parameters('name')]" + "location": { + "value": "[parameters('location')]" }, - "kind": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" }, - "accessMode": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 3000 + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } }, - "storageAccountName": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + "containers": { + "value": [ + { + "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_API_BASE_URL", + "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" + }, + { + "name": "APP_WEB_CLIENT_ID", + "value": "" + }, + { + "name": "APP_WEB_AUTHORITY", + "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" + }, + { + "name": "APP_WEB_SCOPE", + "value": "" + }, + { + "name": "APP_API_SCOPE", + "value": "" + }, + { + "name": "APP_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_POST_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_CONSOLE_LOG_ENABLED", + "value": "false" + } + ] + } + ] } }, "template": { @@ -43301,3965 +47749,3227 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "945327737463253676" + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the file share." + "description": "Required. Name of the Container App." } }, - "managedEnvironmentName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "description": "Optional. Location for all Resources." } }, - "accessMode": { + "kind": { "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], "metadata": { - "description": "Required. The access mode for the storage." + "description": "Optional. Metadata used to render different experiences for resources of the same type." } }, - "kind": { + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { "type": "string", + "defaultValue": "ignore", "allowedValues": [ - "NFS", - "SMB" + "accept", + "ignore", + "require" ], "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." } }, - "storageAccountName": { + "stickySessionsAffinity": { "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], "metadata": { - "description": "Required. Storage account name." + "description": "Optional. Bool indicating if the Container App should enable session affinity." } - } - }, - "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" }, - "storage": { - "type": "Microsoft.App/managedEnvironments/storages", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", - "properties": { - "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", - "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." } - } - }, - "outputs": { - "name": { + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { "type": "string", "metadata": { - "description": "The name of the file share." - }, - "value": "[parameters('name')]" + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } }, - "resourceId": { - "type": "string", + "ipSecurityRestrictions": { + "type": "array", "metadata": { - "description": "The resource ID of the file share." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." }, - "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" + "nullable": true }, - "resourceGroupName": { - "type": "string", + "traffic": { + "type": "array", "metadata": { - "description": "The resource group the file share was deployed into." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_certificate": { - "condition": "[not(empty(parameters('certificate')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" - }, - "managedEnvironmentName": { - "value": "[parameters('name')]" - }, - "certificateKeyVaultProperties": { - "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" - }, - "certificateType": { - "value": "[tryGet(parameters('certificate'), 'certificateType')]" - }, - "certificateValue": { - "value": "[tryGet(parameters('certificate'), 'certificateValue')]" - }, - "certificatePassword": { - "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" - }, - "location": { - "value": "[tryGet(parameters('certificate'), 'location')]" - }, - "tags": { - "value": "[tryGet(parameters('certificate'), 'tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "574133184207535827" + "nullable": true }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." - }, - "definitions": { - "certificateKeyVaultPropertiesType": { + "dapr": { "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } + "description": "Optional. Dapr configuration for the Container App." }, + "nullable": true + }, + "identitySettings": { + "type": "array", "metadata": { - "__bicep_export!": true, - "description": "The type for the certificate's key vault properties." - } - } - }, - "parameters": { - "name": { - "type": "string", + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, "metadata": { - "description": "Required. Name of the Container Apps Managed Environment Certificate." + "description": "Optional. Max inactive revisions a Container App can have." } }, - "managedEnvironmentName": { - "type": "string", + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. The termination grace period for the container app." } }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, "nullable": true, "metadata": { - "description": "Optional. A key vault reference to the certificate to use for the custom domain." + "description": "Optional. The secrets of the Container App." } }, - "certificateType": { + "revisionSuffix": { "type": "string", "nullable": true, - "allowedValues": [ - "ServerSSLCertificate", - "ImagePullTrustedCA" - ], "metadata": { - "description": "Optional. The type of the certificate." + "description": "Optional. User friendly suffix that is appended to the revision name." } }, - "certificateValue": { + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." + "description": "Optional. Workload profile name to pin for container app execution." } }, - "certificatePassword": { - "type": "securestring", + "authConfig": { + "$ref": "#/definitions/authConfigType", "nullable": true, "metadata": { - "description": "Optional. The password of the certificate." + "description": "Optional. The name of the Container App Auth configs." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "managedEnvironmentCertificate": { - "type": "Microsoft.App/managedEnvironments/certificates", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", "location": "[parameters('location')]", + "identity": "[variables('identity')]", "properties": { - "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", - "certificateType": "[parameters('certificateType')]", - "password": "[parameters('certificatePassword')]", - "value": "[parameters('certificateValue')]" - }, - "tags": "[parameters('tags')]" - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key values." + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "value": "[parameters('name')]" + "dependsOn": [ + "containerApp" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key values." + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, - "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + "dependsOn": [ + "containerApp" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the certificate was deployed into." + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Managed Environment was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Managed Environment." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Managed Environment." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" - }, - "defaultDomain": { - "type": "string", - "metadata": { - "description": "The Default domain of the Managed Environment." - }, - "value": "[reference('managedEnvironment').defaultDomain]" - }, - "staticIp": { - "type": "string", - "metadata": { - "description": "The IP address of the Managed Environment." - }, - "value": "[reference('managedEnvironment').staticIp]" - }, - "domainVerificationId": { - "type": "string", - "metadata": { - "description": "The domain verification id for custom domains." - }, - "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "avmContainerRegistryReader": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." - }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "isolationScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], - "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" - }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" - }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" - }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "1387931959101373036" + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } }, - "parameters": { - "userAssignedIdentityName": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." - } + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "Required. The name of the secret." - } - }, - "audiences": { - "type": "array", - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." - } + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "issuer": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." - } + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." - } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" - } - } - ], - "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the federated identity credential." + "description": "The name of the Container App." }, "value": "[parameters('name')]" }, - "resourceId": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource ID of the federated identity credential." + "description": "The principal ID of the system assigned identity." }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The name of the resource group the federated identity credential was created in." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } }, "dependsOn": [ - "userAssignedIdentity" + "avmContainerApp_API", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - }, - "avmContainerApp": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" + "avmContainerApp_Workflow": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" + "location": { + "value": "[parameters('location')]" }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + "workloadProfileName": { + "value": "Consumption" }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" + "registries": { + "value": null }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "tags": { + "value": "[parameters('tags')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "activeRevisionsMode": { + "value": "Single" }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } } }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "name": "Container Apps", + "description": "This module deploys a Container App." }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Required. Name of the Container App." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Location for all Resources." + } }, - "globalValidation": { - "type": "object", + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } }, - "httpSettings": { - "type": "object", + "disableIngress": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Bool to disable all ingress traffic for the container app." + } }, - "identityProviders": { - "type": "object", + "ingressExternal": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } }, - "login": { + "service": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "description": "Optional. Dev ContainerApp service type." }, "nullable": true }, - "platform": { - "type": "object", + "includeAddOns": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } }, - "enableTelemetry": { + "ingressAllowInsecure": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." } - } - }, - "outputs": { - "name": { + }, + "activeRevisionsMode": { "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" + "description": "Optional. Controls how active revisions are handled for the Container app." + } }, - "resourceId": { + "environmentResourceId": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "nullable": true }, - "resourceGroupName": { - "type": "string", + "registries": { + "type": "array", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_API": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 - } - ] - } - ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" - } - } - } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "containerApp" + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + "avmCosmosDB": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "mongodbDatabases": { + "value": [ + { + "name": "default", + "tag": "default database" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "databaseAccountOfferType": { + "value": "Standard" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "enableAutomaticFailover": { + "value": false }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "serverVersion": { + "value": "7.0" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "capabilitiesToAdd": { + "value": [ + "EnableMongo" + ] }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "defaultConsistencyLevel": { + "value": "Session" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } + "maxIntervalInSeconds": { + "value": 5 + }, + "maxStalenessPrefix": { + "value": 100 + }, + "zoneRedundant": { + "value": false + }, + "networkRestrictions": { + "value": { + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", + "ipRules": [], + "virtualNetworkRules": [] + } + }, + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -47268,6045 +50978,5178 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" + "version": "0.40.2.10011", + "templateHash": "1772014800591596213" + }, + "name": "Azure Cosmos DB account", + "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group ID for the private endpoint group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses for the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "failoverLocationType": { + "type": "object", + "properties": { + "failoverPriority": { + "type": "int", + "metadata": { + "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." + } + }, + "isZoneRedundant": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." + } + }, + "locationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the region." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the failover location." + } + }, + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." + } + }, + "sqlRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/nestedSqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." + } + }, + "networkRestrictionType": { + "type": "object", + "properties": { + "ipRules": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." + } + }, + "networkAclBypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." + } + }, + "publicNetworkAccess": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." + } + }, + "virtualNetworkRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of a subnet." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." + } + }, + "networkAclBypassResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network restriction." + } + }, + "gremlinDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a gremlin databae." + } }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { - "type": "string", + "mongoDbType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for a mongo databae." } }, - "encryptionSettings": { + "sqlDatabaseType": { "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "__bicep_export!": true, + "description": "The type for a sql database." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } }, - "nullable": true + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "cassandraStandaloneRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." + } }, - "globalValidation": { + "cassandraRoleDefinitionType": { "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "cassandraKeyspaceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraTableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraViewType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + } }, - "nullable": true + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB Cassandra keyspace." + } }, - "httpSettings": { + "defaultIdentityType": { "type": "object", + "discriminator": { + "propertyName": "name", + "mapping": { + "FirstPartyIdentity": { + "$ref": "#/definitions/defaultIdentityFirstPartyType" + }, + "SystemAssignedIdentity": { + "$ref": "#/definitions/defaultIdentitySystemAssignedType" + }, + "UserAssignedIdentity": { + "$ref": "#/definitions/defaultIdentityUserAssignedType" + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "__bicep_export!": true, + "description": "The type for the default identity." + } + }, + "defaultIdentityFirstPartyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "FirstPartyIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentitySystemAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "SystemAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentityUserAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "UserAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the user assigned identity to use as the default identity." + } + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "identityProviders": { + "_1.privateEndpointIpConfigurationType": { "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "login": { + "cassandraRoleAssignmentType": { "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-role-definition/main.bicep" + } + } + }, + "cassandraTableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "description": "The type of a Cassandra table.", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "tableType" + } + } + }, + "cassandraViewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } }, - "nullable": true + "metadata": { + "description": "The type of a Cassandra view (materialized view).", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "viewType" + } + } }, - "platform": { + "collectionType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "description": "The type of a collection.", + "__bicep_imported_from!": { + "sourceTemplate": "mongodb-database/main.bicep" } } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "containerType": { + "type": "object", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_Web": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "ingressExternal": { - "value": true - }, - "ingressTargetPort": { - "value": 3000 - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" - } - } - } - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_API_BASE_URL", - "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" - }, - { - "name": "APP_WEB_CLIENT_ID", - "value": "" - }, - { - "name": "APP_WEB_AUTHORITY", - "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" - }, - { - "name": "APP_WEB_SCOPE", - "value": "" - }, - { - "name": "APP_API_SCOPE", - "value": "" - }, - { - "name": "APP_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_POST_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_CONSOLE_LOG_ENABLED", - "value": "false" - } - ] - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The type of a container.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-database/main.bicep" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { - "type": "string", + "customerManagedKeyAndVaultOnlyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "encryptionSettings": { + "diagnosticSettingFullType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "graphType": { + "type": "object", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp_API", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_Workflow": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "description": "The type of a graph.", + "__bicep_imported_from!": { + "sourceTemplate": "gremlin-database/main.bicep" + } + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "nestedSqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The type for the SQL Role Assignments.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-role-definition/main.bicep", + "originalIdentifier": "sqlRoleAssignmentType" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Required. The name of the account." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Defaults to the current resource group scope location. Location for all resources." + } }, - "globalValidation": { + "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "description": "Optional. Tags for the resource." }, "nullable": true }, - "httpSettings": { - "type": "object", + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. The managed identity definition for this resource." + } }, - "identityProviders": { - "type": "object", + "databaseAccountOfferType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "description": "Optional. The offer type for the account. Defaults to \"Standard\"." + } + }, + "failoverLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/failoverLocationType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." + } }, - "login": { - "type": "object", + "zoneRedundant": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." + } }, - "platform": { - "type": "object", + "defaultConsistencyLevel": { + "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." + } }, - "enableTelemetry": { + "disableLocalAuthentication": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + }, + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions. Defaults to true." + } }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" + "enableFreeTier": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." } - } - }, - "outputs": { - "name": { - "type": "string", + }, + "enableMultipleWriteLocations": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" + "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." + } }, - "resourceId": { - "type": "string", + "disableKeyBasedMetadataWriteAccess": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." + } }, - "resourceGroupName": { + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." + } + }, + "serverVersion": { "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2", + "5.0", + "6.0", + "7.0" + ], "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmCosmosDB": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "mongodbDatabases": { - "value": [ - { - "name": "default", - "tag": "default database" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "databaseAccountOfferType": { - "value": "Standard" - }, - "enableAutomaticFailover": { - "value": false - }, - "serverVersion": { - "value": "7.0" - }, - "capabilitiesToAdd": { - "value": [ - "EnableMongo" - ] - }, - "defaultConsistencyLevel": { - "value": "Session" - }, - "maxIntervalInSeconds": { - "value": 5 - }, - "maxStalenessPrefix": { - "value": 100 - }, - "zoneRedundant": { - "value": false - }, - "networkRestrictions": { - "value": { - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", - "ipRules": [], - "virtualNetworkRules": [] - } - }, - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1772014800591596213" - }, - "name": "Azure Cosmos DB account", - "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group ID for the private endpoint group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." - } + "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." + } + }, + "sqlDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlDatabaseType" }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses for the private endpoint." - } + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "failoverLocationType": { - "type": "object", - "properties": { - "failoverPriority": { - "type": "int", - "metadata": { - "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." - } - }, - "isZoneRedundant": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." - } - }, - "locationName": { - "type": "string", - "metadata": { - "description": "Required. The name of the region." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the failover location." - } - }, - "sqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." - } - }, - "sqlRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of data actions that are allowed." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." - } - }, - "assignments": { - "type": "array", - "items": { - "$ref": "#/definitions/nestedSqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." - } - }, - "networkRestrictionType": { - "type": "object", - "properties": { - "ipRules": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." - } - }, - "networkAclBypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." - } - }, - "publicNetworkAccess": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." - } - }, - "virtualNetworkRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of a subnet." - } + }, + "mongodbDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/mongoDbType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." - } - }, - "networkAclBypassResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network restriction." - } - }, - "gremlinDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" }, - "description": "Optional. Tags of the Gremlin database resource." - }, - "nullable": true - }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a gremlin databae." - } - }, - "mongoDbType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "items": { - "$ref": "#/definitions/collectionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "autoscaleSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + "gremlinDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/gremlinDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." + } }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." - }, - "nullable": true - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." + } }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a mongo databae." - } - }, - "sqlDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + "cassandraKeyspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraKeyspaceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." + } }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a sql database." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } - }, - "cassandraStandaloneRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." - } - }, - "cassandraRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." - } - }, - "notDataActions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." - } - }, - "assignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." - } - }, - "cassandraKeyspaceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra keyspace." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraTableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." - } - }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraViewType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + "totalThroughputLimit": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." + } }, - "description": "Optional. Tags of the Cassandra keyspace resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB Cassandra keyspace." - } - }, - "defaultIdentityType": { - "type": "object", - "discriminator": { - "propertyName": "name", - "mapping": { - "FirstPartyIdentity": { - "$ref": "#/definitions/defaultIdentityFirstPartyType" - }, - "SystemAssignedIdentity": { - "$ref": "#/definitions/defaultIdentitySystemAssignedType" - }, - "UserAssignedIdentity": { - "$ref": "#/definitions/defaultIdentityUserAssignedType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the default identity." - } - }, - "defaultIdentityFirstPartyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "FirstPartyIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - } - } - }, - "defaultIdentitySystemAssignedType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "SystemAssignedIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - } - } - }, - "defaultIdentityUserAssignedType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "UserAssignedIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the user assigned identity to use as the default identity." - } - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of control plane Azure role-based access control assignments." + } + }, + "sqlRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." + } + }, + "cassandraRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings for the service." + } + }, + "capabilitiesToAdd": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless", + "EnableNoSQLVectorSearch", + "EnableNoSQLFullTextSearch", + "EnableMaterializedViews", + "DeleteAllItemsByPartitionKey" + ], + "metadata": { + "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." + } + }, + "backupPolicyType": { "type": "string", + "defaultValue": "Continuous", + "allowedValues": [ + "Periodic", + "Continuous" + ], "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." } }, - "memberName": { + "backupPolicyContinuousTier": { "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], + "metadata": { + "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." + } + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." + } + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." } }, - "privateIPAddress": { + "backupStorageRedundancy": { "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "cassandraRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-role-definition/main.bicep" - } - } - }, - "cassandraTableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "schema": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" }, - "description": "Required. Schema definition for the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + "networkRestrictions": { + "$ref": "#/definitions/networkRestrictionType", + "defaultValue": { + "ipRules": [], + "virtualNetworkRules": [], + "publicNetworkAccess": "Disabled" + }, + "metadata": { + "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." + } }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Analytical TTL for the table." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." - } - } - }, - "metadata": { - "description": "The type of a Cassandra table.", - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "tableType" - } - } - }, - "cassandraViewType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the view." - } - }, - "viewDefinition": { - "type": "string", - "metadata": { - "description": "Required. View definition (CQL statement)." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + "minimumTlsVersion": { + "type": "string", + "defaultValue": "Tls12", + "allowedValues": [ + "Tls12" + ], + "metadata": { + "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." + } }, - "description": "Optional. Tags for the view." - }, - "nullable": true - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." - } - } - }, - "metadata": { - "description": "The type of a Cassandra view (materialized view).", - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "viewType" - } - } - }, - "collectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + "enableBurstCapacity": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." + } }, - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + "enableCassandraConnector": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." + } }, - "description": "Required. ShardKey for the collection." - } - } - }, - "metadata": { - "description": "The type of a collection.", - "__bicep_imported_from!": { - "sourceTemplate": "mongodb-database/main.bicep" - } - } - }, - "containerType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + "enablePartitionMerge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." + } }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + "enablePerRegionPerPartitionAutoscale": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." + } + }, + "analyticalStorageConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" + }, + "description": "Optional. Analytical storage specific properties." + }, + "nullable": true + }, + "cors": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" + }, + "description": "Optional. The CORS policy for the Cosmos DB database account." + }, + "nullable": true }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "defaultIdentity": { + "$ref": "#/definitions/defaultIdentityType", + "defaultValue": { + "name": "FirstPartyIdentity" + }, + "metadata": { + "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." + } }, - "description": "Optional. Indexing policy of the container." + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." + } + } }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInControlPlaneRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" }, - "nullable": true - }, - "kind": { - "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - } - }, - "metadata": { - "description": "The type of a container.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-database/main.bicep" - } - } - }, - "customerManagedKeyAndVaultOnlyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } + } + }, + "cMKKeyVault": { + "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" + }, + "databaseAccount": { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", + "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", + "dependsOn": [ + "cMKKeyVault::cMKKey" + ] + }, + "databaseAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_diagnosticSettings": { + "copy": { + "name": "databaseAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_roleAssignments": { + "copy": { + "name": "databaseAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlDatabases": { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "3972888645334640168" + }, + "name": "DocumentDB Database Account SQL Databases", + "description": "This module deploys a SQL Database in a CosmosDB Account." + }, + "definitions": { + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a container." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "container": { + "copy": { + "name": "container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "conflictResolutionPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + }, + "defaultTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "kind": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + }, + "paths": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + }, + "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", + "uniqueKeyPolicyKeys": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "4781880351108045502" + }, + "name": "DocumentDB Database Account SQL Database Containers", + "description": "This module deploys a SQL Database Container in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "variables": { + "copy": [ + { + "name": "partitionKeyPaths", + "count": "[length(parameters('paths'))]", + "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + } + ] + }, + "resources": { + "databaseAccount::sqlDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "container": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "graphType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + "databaseAccount_sqlRoleDefinitions": { + "copy": { + "name": "databaseAccount_sqlRoleDefinitions", + "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "dataActions": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" + }, + "roleName": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "sqlRoleAssignments": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "8514367433037227852" + }, + "name": "DocumentDB Database Account SQL Role Definitions.", + "description": "This module deploys a SQL Role Definision in a CosmosDB Account." + }, + "definitions": { + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SQL Role Assignments." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionIdOrName": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The role name of the SQL Role Definition." + }, + "value": "[reference('sqlRoleDefinition').roleName]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true - } - }, - "metadata": { - "description": "The type of a graph.", - "__bicep_imported_from!": { - "sourceTemplate": "gremlin-database/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "nestedSqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "description": "The type for the SQL Role Assignments.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-role-definition/main.bicep", - "originalIdentifier": "sqlRoleAssignmentType" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionIdOrName": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_sqlDatabases", + "databaseAccount_sqlRoleDefinitions" + ] }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the account." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Defaults to the current resource group scope location. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the resource." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "databaseAccountOfferType": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard" - ], - "metadata": { - "description": "Optional. The offer type for the account. Defaults to \"Standard\"." - } - }, - "failoverLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/failoverLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." - } - }, - "defaultConsistencyLevel": { - "type": "string", - "defaultValue": "Session", - "allowedValues": [ - "Eventual", - "ConsistentPrefix", - "Session", - "BoundedStaleness", - "Strong" - ], - "metadata": { - "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." - } - }, - "disableLocalAuthentication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." - } - }, - "enableAnalyticalStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." - } - }, - "enableAutomaticFailover": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable automatic failover for regions. Defaults to true." - } - }, - "enableFreeTier": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." - } - }, - "enableMultipleWriteLocations": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." - } - }, - "disableKeyBasedMetadataWriteAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." - } - }, - "maxStalenessPrefix": { - "type": "int", - "defaultValue": 100000, - "minValue": 1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." - } - }, - "maxIntervalInSeconds": { - "type": "int", - "defaultValue": 300, - "minValue": 5, - "maxValue": 86400, - "metadata": { - "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." - } - }, - "serverVersion": { - "type": "string", - "defaultValue": "4.2", - "allowedValues": [ - "3.2", - "3.6", - "4.0", - "4.2", - "5.0", - "6.0", - "7.0" - ], - "metadata": { - "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." - } - }, - "sqlDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlDatabaseType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." - } - }, - "mongodbDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/mongoDbType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." - } - }, - "gremlinDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/gremlinDatabaseType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." - } - }, - "cassandraKeyspaces": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraKeyspaceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "totalThroughputLimit": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of control plane Azure role-based access control assignments." - } - }, - "sqlRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleDefinitionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." - } - }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." - } - }, - "cassandraRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleDefinitionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." - } - }, - "cassandraRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings for the service." - } - }, - "capabilitiesToAdd": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "allowedValues": [ - "EnableCassandra", - "EnableTable", - "EnableGremlin", - "EnableMongo", - "DisableRateLimitingResponses", - "EnableServerless", - "EnableNoSQLVectorSearch", - "EnableNoSQLFullTextSearch", - "EnableMaterializedViews", - "DeleteAllItemsByPartitionKey" - ], - "metadata": { - "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." - } - }, - "backupPolicyType": { - "type": "string", - "defaultValue": "Continuous", - "allowedValues": [ - "Periodic", - "Continuous" - ], - "metadata": { - "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." - } - }, - "backupPolicyContinuousTier": { - "type": "string", - "defaultValue": "Continuous30Days", - "allowedValues": [ - "Continuous30Days", - "Continuous7Days" - ], - "metadata": { - "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." - } - }, - "backupIntervalInMinutes": { - "type": "int", - "defaultValue": 240, - "minValue": 60, - "maxValue": 1440, - "metadata": { - "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." - } - }, - "backupRetentionIntervalInHours": { - "type": "int", - "defaultValue": 8, - "minValue": 2, - "maxValue": 720, - "metadata": { - "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." - } - }, - "backupStorageRedundancy": { - "type": "string", - "defaultValue": "Local", - "allowedValues": [ - "Geo", - "Local", - "Zone" - ], - "metadata": { - "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." - } - }, - "networkRestrictions": { - "$ref": "#/definitions/networkRestrictionType", - "defaultValue": { - "ipRules": [], - "virtualNetworkRules": [], - "publicNetworkAccess": "Disabled" - }, - "metadata": { - "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "Tls12", - "allowedValues": [ - "Tls12" - ], - "metadata": { - "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." - } - }, - "enableBurstCapacity": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." - } - }, - "enableCassandraConnector": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." - } - }, - "enablePartitionMerge": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." - } - }, - "enablePerRegionPerPartitionAutoscale": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." - } - }, - "analyticalStorageConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" - }, - "description": "Optional. Analytical storage specific properties." - }, - "nullable": true - }, - "cors": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" - }, - "description": "Optional. The CORS policy for the Cosmos DB database account." - }, - "nullable": true - }, - "defaultIdentity": { - "$ref": "#/definitions/defaultIdentityType", - "defaultValue": { - "name": "FirstPartyIdentity" - }, - "metadata": { - "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInControlPlaneRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", - "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", - "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", - "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", - "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" - }, - "databaseAccount": { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", - "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", - "dependsOn": [ - "cMKKeyVault::cMKKey" - ] - }, - "databaseAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_diagnosticSettings": { - "copy": { - "name": "databaseAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_roleAssignments": { - "copy": { - "name": "databaseAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlDatabases": { - "copy": { - "name": "databaseAccount_sqlDatabases", - "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" - }, - "containers": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" - }, - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "3972888645334640168" + "databaseAccount_cassandraRoleDefinitions": { + "copy": { + "name": "databaseAccount_cassandraRoleDefinitions", + "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "roleName": { + "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "dataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" + }, + "notDataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "cassandraRoleAssignments": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10787709019875067397" + }, + "name": "DocumentDB Database Account Cassandra Role Definitions.", + "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." + }, + "definitions": { + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]", + "notDataActions": "[parameters('notDataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cassandra role definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cassandra role definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the cassandra role definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_cassandraKeyspaces", + "databaseAccount_cassandraRoleDefinitions" + ] + }, + "databaseAccount_mongodbDatabases": { + "copy": { + "name": "databaseAccount_mongodbDatabases", + "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "collections": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "autoscaleSettings": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "13897098552792121791" + }, + "name": "DocumentDB Database Account MongoDB Databases", + "description": "This module deploys a MongoDB Database within a CosmosDB Account." + }, + "definitions": { + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a collection." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "mongodbDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "mongodbDatabase_collections": { + "copy": { + "name": "mongodbDatabase_collections", + "count": "[length(coalesce(parameters('collections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "mongodbDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + }, + "indexes": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + }, + "shardKey": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "16151461445994734468" + }, + "name": "DocumentDB Database Account MongoDB Database Collections", + "description": "This module deploys a MongoDB Database Collection." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "mongodbDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]", + "indexes": "[parameters('indexes')]", + "shardKey": "[parameters('shardKey')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database collection." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database collection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "mongodbDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "name": "DocumentDB Database Account SQL Databases", - "description": "This module deploys a SQL Database in a CosmosDB Account." - }, - "definitions": { - "containerType": { - "type": "object", + "databaseAccount_gremlinDatabases": { + "copy": { + "name": "databaseAccount_gremlinDatabases", + "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", "properties": { - "name": { - "type": "string", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "graphs": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. Name of the container." + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11959636451300474346" + }, + "name": "DocumentDB Database Account Gremlin Databases", + "description": "This module deploys a Gremlin Database within a CosmosDB Account." + }, + "definitions": { + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a graph." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + } + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "gremlinDatabase_gremlinGraphs": { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(coalesce(parameters('graphs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "partitionKeyPaths": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10487122333182352122" + }, + "name": "DocumentDB Database Accounts Gremlin Databases Graphs", + "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount::gremlinDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinGraph": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": "[parameters('indexingPolicy')]", + "partitionKey": { + "paths": "[parameters('partitionKeyPaths')]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "gremlinDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_tables": { + "copy": { + "name": "databaseAccount_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" } }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1787500858429182824" + }, + "name": "Azure Cosmos DB account tables", + "description": "This module deploys a table within an Azure Cosmos DB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "table": { + "type": "Microsoft.DocumentDB/databaseAccounts/tables", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraKeyspaces": { + "copy": { + "name": "databaseAccount_cassandraKeyspaces", + "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "conflictResolutionPolicy": { - "type": "object", + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" + }, + "views": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15257396763463366586" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces", + "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." + }, + "definitions": { + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra table." + } + }, + "viewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra view (materialized view)." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/viewType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + "autoscaleSettingsMaxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { - "type": "array", - "items": { - "type": "string" + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + } }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + "cassandraKeyspace": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + "cassandraKeyspace_tables": { + "copy": { + "name": "cassandraKeyspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "schema": { + "value": "[parameters('tables')[copyIndex()].schema]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + }, + "throughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "defaultTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15998065591386988132" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Tables", + "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra table resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the Cassandra table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "defaultTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraTable": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "schema": "[parameters('schema')]", + "defaultTtl": "[parameters('defaultTtl')]", + "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + }, + "cassandraKeyspace_views": { + "copy": { + "name": "cassandraKeyspace_views", + "count": "[length(parameters('views'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('views')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "viewDefinition": { + "value": "[parameters('views')[copyIndex()].viewDefinition]" + }, + "throughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6617803098467821091" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Views", + "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra view." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags of the Cassandra view resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraView": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "viewDefinition": "[parameters('viewDefinition')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra view." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra view." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra view was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + } }, - "nullable": true - }, - "kind": { - "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra keyspace." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra keyspace." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra keyspace was created in." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a container." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, "dependsOn": [ "databaseAccount" ] }, - "container": { + "databaseAccount_privateEndpoints": { "copy": { - "name": "container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" + "name": "databaseAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, - "sqlDatabaseName": { - "value": "[parameters('name')]" + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" }, - "analyticalStorageTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, - "conflictResolutionPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, - "defaultTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "kind": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, - "version": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" }, - "paths": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" }, - "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", - "uniqueKeyPolicyKeys": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -53316,571 +56159,602 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "4781880351108045502" + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } }, - "name": "DocumentDB Database Account SQL Database Containers", - "description": "This module deploys a SQL Database Container in a CosmosDB Account." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "sqlDatabaseName": { + "subnetResourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "name": { - "type": "string", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. Name of the container." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "conflictResolutionPolicy": { - "type": "object", + "ipConfigurations": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." }, "nullable": true }, - "defaultTtl": { - "type": "int", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "nullable": true, - "minValue": -1, - "maxValue": 2147483647, "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, - "throughput": { - "type": "int", - "defaultValue": 400, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. Location for all Resources." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, - "maxValue": 1000000, "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" }, - "description": "Optional. Tags of the SQL Database resource." + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." }, "nullable": true }, - "paths": { + "customDnsConfigs": { "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" }, - "description": "Optional. Indexing policy of the container." + "description": "Optional. Custom DNS configurations." }, "nullable": true }, - "uniqueKeyPolicyKeys": { + "manualPrivateLinkServiceConnections": { "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." }, "nullable": true }, - "kind": { - "type": "string", - "defaultValue": "Hash", - "allowedValues": [ - "Hash", - "MultiHash" - ], + "privateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true }, - "version": { - "type": "int", - "defaultValue": 1, - "allowedValues": [ - 1, - 2 - ], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "variables": { "copy": [ { - "name": "partitionKeyPaths", - "count": "[length(parameters('paths'))]", - "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } - ] + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } }, "resources": { - "databaseAccount::sqlDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "container": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the container was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "sqlDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlRoleDefinitions": { - "copy": { - "name": "databaseAccount_sqlRoleDefinitions", - "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "dataActions": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" - }, - "roleName": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "sqlRoleAssignments": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "8514367433037227852" - }, - "name": "DocumentDB Database Account SQL Role Definitions.", - "description": "This module deploys a SQL Role Definision in a CosmosDB Account." - }, - "definitions": { - "sqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SQL Role Assignments." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the Role Definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of data actions that are allowed." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." - } - }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", - "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ - { - "dataActions": "[parameters('dataActions')]" - } - ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" - } - }, - "databaseAccount_sqlRoleAssignments": { - "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "roleDefinitionIdOrName": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } } }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" } } } - } - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" - } + }, + "dependsOn": [ + "privateEndpoint" + ] } }, "outputs": { - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the SQL Role Assignment." + "description": "The resource group the private endpoint was deployed into." }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the SQL Role Assignment." + "description": "The resource ID of the private endpoint." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." + "description": "The name of the private endpoint." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } }, "dependsOn": [ - "sqlRoleDefinition" + "databaseAccount" ] } }, @@ -53888,69 +56762,158 @@ "name": { "type": "string", "metadata": { - "description": "The name of the SQL Role Definition." + "description": "The name of the database account." }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the SQL Role Definition." + "description": "The resource ID of the database account." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." + "description": "The name of the resource group the database account was created in." }, "value": "[resourceGroup().name]" }, - "roleName": { + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" + }, + "endpoint": { "type": "string", "metadata": { - "description": "The role name of the SQL Role Definition." + "description": "The endpoint of the database account." + }, + "value": "[reference('databaseAccount').documentEndpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "primaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" + }, + "primaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" + }, + "primaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" + }, + "primaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" + }, + "secondaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" + }, + "secondaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" + }, + "secondaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" + }, + "secondaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only connection string." }, - "value": "[reference('sqlRoleDefinition').roleName]" + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" } } } }, "dependsOn": [ - "databaseAccount" + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", + "virtualNetwork" ] }, - "databaseAccount_sqlRoleAssignments": { - "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" - }, + "avmAiSearch": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "roleDefinitionIdOrName": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + "name": { + "value": "[format('srch-{0}', variables('solutionSuffix'))]" }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + "location": { + "value": "[parameters('location')]" }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + "skuName": { + "value": "basic" }, - "scope": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -53960,322 +56923,204 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + "version": "0.42.1.51946", + "templateHash": "8530209533589901450" + } }, "parameters": { - "databaseAccountName": { + "solutionName": { "type": "string", + "minLength": 3, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Solution name suffix used to derive the resource name." } }, "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." } }, - "roleDefinitionIdOrName": { + "location": { "type": "string", "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." + "description": "Azure region for the resource." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Tags to apply to the resource." } }, - "scope": { + "skuName": { "type": "string", - "nullable": true, + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + "description": "SKU name for the search service." } - } - }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." } }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" - } - } - }, - "outputs": { - "name": { - "type": "string", + "partitionCount": { + "type": "int", + "defaultValue": 1, "metadata": { - "description": "The name of the SQL Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + "description": "Number of partitions." + } }, - "resourceId": { + "hostingMode": { "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], "metadata": { - "description": "The resource ID of the SQL Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + "description": "Hosting mode." + } }, - "resourceGroupName": { + "semanticSearch": { "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_sqlDatabases", - "databaseAccount_sqlRoleDefinitions" - ] - }, - "databaseAccount_cassandraRoleDefinitions": { - "copy": { - "name": "databaseAccount_cassandraRoleDefinitions", - "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "roleName": { - "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "dataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" - }, - "notDataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "cassandraRoleAssignments": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10787709019875067397" - }, - "name": "DocumentDB Database Account Cassandra Role Definitions.", - "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." - }, - "definitions": { - "cassandraRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_export!": true + "description": "Semantic search tier." } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Whether to disable local authentication." } }, - "name": { + "managedIdentityType": { "type": "string", - "nullable": true, + "defaultValue": "SystemAssigned", "metadata": { - "description": "Optional. The unique identifier of the Role Definition." + "description": "Managed identity type for the search service." } }, - "roleName": { + "publicNetworkAccess": { "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + "description": "Public network access setting." } }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "notDataActions": { + "diagnosticSettings": { "type": "array", - "items": { - "type": "string" - }, "defaultValue": [], "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + "description": "Diagnostic settings for monitoring." } }, - "assignableScopes": { + "privateEndpoints": { "type": "array", - "items": { - "type": "string" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + "description": "Private endpoint configurations." } }, - "cassandraRoleAssignments": { + "roleAssignments": { "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + "description": "Optional. Array of role assignments to create on the AI Search service." } } }, "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", - "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ - { - "dataActions": "[parameters('dataActions')]", - "notDataActions": "[parameters('notDataActions')]" - } - ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" } }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, + "searchServiceUpdate": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('avm.res.search.update.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[parameters('name')]" }, - "roleDefinitionId": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + "location": { + "value": "[parameters('location')]" }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "sku": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + "managedIdentities": { + "value": { + "systemAssigned": "[equals(parameters('managedIdentityType'), 'SystemAssigned')]" + } }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" - } + "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -54284,605 +57129,2304 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" + "version": "0.39.26.7824", + "templateHash": "6207719545398489494" + }, + "name": "Search Services", + "description": "This module deploys a Search Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the API Admin keys generated by the modules." + } + }, + "primaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAdminKey secret name to create." + } + }, + "secondaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAdminKey secret name to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } + } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." } }, - "name": { + "authOptions": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/authOptions" + }, + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + }, + "nullable": true + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "computeType": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Confidential", + "Default" + ], + "metadata": { + "description": "Optional. The compute type of the search service." + } + }, + "cmkEnforcement": { "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "dataExfiltrationProtections": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, + "allowedValues": [ + "All" + ], "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + "description": "Optional. A list of data exfiltration scenarios that are explicitly disallowed for the search service. Currently, the only supported value is 'All' to disable all possible data export scenarios with more fine grained controls planned for the future." } }, - "principalId": { + "hostingMode": { "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." } }, - "roleDefinitionId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." + "description": "Optional. Location for all Resources." } }, - "scope": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings for all Resources in the solution." + } + }, + "networkRuleSet": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/networkRuleSet" + }, + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + }, + "nullable": true + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } + }, + "publicNetworkAccess": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", "nullable": true, "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to help categorize the resource in the Azure portal." + }, + "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', '')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + "authOptions": "[parameters('authOptions')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]", + "computeType": "[parameters('computeType')]", + "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra Role Assignment." + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + "dependsOn": [ + "searchService" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "2115224445601868607" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource." + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "cassandraRoleDefinition" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cassandra role definition." - }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cassandra role definition." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the cassandra role definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" - }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_cassandraKeyspaces", - "databaseAccount_cassandraRoleDefinitions" - ] - }, - "databaseAccount_mongodbDatabases": { - "copy": { - "name": "databaseAccount_mongodbDatabases", - "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "collections": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" - }, - "autoscaleSettings": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "13897098552792121791" - }, - "name": "DocumentDB Database Account MongoDB Databases", - "description": "This module deploys a MongoDB Database within a CosmosDB Account." - }, - "definitions": { - "collectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a collection." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "items": { - "$ref": "#/definitions/collectionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "autoscaleSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" - }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "mongodbDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "mongodbDatabase_collections": { - "copy": { - "name": "mongodbDatabase_collections", - "count": "[length(coalesce(parameters('collections'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "mongodbDatabaseName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" - }, - "indexes": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" - }, - "shardKey": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "16151461445994734468" + "dependsOn": [ + "searchService" + ] }, - "name": "DocumentDB Database Account MongoDB Database Collections", - "description": "This module deploys a MongoDB Database Collection." + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "696453183181258843" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } }, - "parameters": { - "databaseAccountName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." - } + "description": "The name of the search service." + }, + "value": "[parameters('name')]" }, - "mongodbDatabaseName": { + "resourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." - } + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. Name of the collection." - } + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" }, - "throughput": { - "type": "int", - "defaultValue": 400, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" }, - "indexes": { - "type": "array", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2025-05-01', 'full').location]" }, - "shardKey": { - "type": "object", + "endpoint": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", - "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]", - "indexes": "[parameters('indexes')]", - "shardKey": "[parameters('shardKey')]" + "description": "The endpoint of the search service." + }, + "value": "[reference('searchService').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" } } - } - ], - "outputs": { - "name": { - "type": "string", + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "The name of the mongodb database collection." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": "[parameters('name')]" + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "resourceId": { - "type": "string", + "primaryKey": { + "type": "securestring", "metadata": { - "description": "The resource ID of the mongodb database collection." + "description": "The primary admin API key of the search service." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" }, - "resourceGroupName": { - "type": "string", + "secondaryKey": { + "type": "securestring", "metadata": { - "description": "The name of the resource group the mongodb database collection was created in." + "description": "The secondaryKey admin API key of the search service." }, - "value": "[resourceGroup().name]" + "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" } } } }, "dependsOn": [ - "mongodbDatabase" + "searchService" ] } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the mongodb database." + "description": "Name of the AI Search service." }, "value": "[parameters('name')]" }, - "resourceId": { + "endpoint": { "type": "string", "metadata": { - "description": "The resource ID of the mongodb database." + "description": "Endpoint URL of the AI Search service." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" }, - "resourceGroupName": { + "identityPrincipalId": { "type": "string", "metadata": { - "description": "The name of the resource group the mongodb database was created in." + "description": "System-assigned identity principal ID." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" } } } - }, - "dependsOn": [ - "databaseAccount" - ] + } }, - "databaseAccount_gremlinDatabases": { - "copy": { - "name": "databaseAccount_gremlinDatabases", - "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" - }, + "avmAppConfig": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", + "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('location')]" + } + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } }, - "graphs": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + "sku": { + "value": "Standard" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "disableLocalAuth": { + "value": false + }, + "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + } + ] }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_PROCESS", + "value": "Processes" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMA", + "value": "Schemas" + }, + { + "name": "APP_COSMOS_DATABASE", + "value": "ContentProcess" + }, + { + "name": "APP_CPS_CONFIGURATION", + "value": "cps-configuration" + }, + { + "name": "APP_CPS_MAX_FILESIZE_MB", + "value": "20" + }, + { + "name": "APP_CPS_PROCESSES", + "value": "cps-processes" + }, + { + "name": "APP_MESSAGE_QUEUE_EXTRACT", + "value": "content-pipeline-extract-queue" + }, + { + "name": "APP_MESSAGE_QUEUE_INTERVAL", + "value": "5" + }, + { + "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", + "value": "180" + }, + { + "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", + "value": "10" + }, + { + "name": "APP_PROCESS_STEPS", + "value": "extract,map,evaluate,save" + }, + { + "name": "APP_STORAGE_BLOB_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" + }, + { + "name": "APP_STORAGE_QUEUE_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" + }, + { + "name": "APP_COSMOS_CONNSTR", + "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", + "value": "claimprocesses" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCHES", + "value": "batches" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMASET", + "value": "Schemasets" + }, + { + "name": "APP_CPS_PROCESS_BATCH", + "value": "process-batch" + }, + { + "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", + "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" + }, + { + "name": "APP_CPS_POLL_INTERVAL_SECONDS", + "value": "3" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference('avmStorageAccount').outputs.name.value]" + }, + { + "name": "CLAIM_PROCESS_QUEUE_NAME", + "value": "claim-process-queue" + }, + { + "name": "DEAD_LETTER_QUEUE_NAME", + "value": "claim-process-dead-letter-queue" + }, + { + "name": "AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", + "value": "[parameters('gptModelName')]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_OPENAI_ENDPOINT_BASE", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", + "value": "" + }, + { + "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", + "value": "" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + }, + { + "name": "GLOBAL_LLM_SERVICE", + "value": "AzureOpenAI" + }, + { + "name": "GPT5_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "GPT5_CHAT_DEPLOYMENT_NAME", + "value": "gpt-5" + }, + { + "name": "GPT5_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "PHI4_API_VERSION", + "value": "2024-05-01-preview" + }, + { + "name": "PHI4_CHAT_DEPLOYMENT_NAME", + "value": "phi-4" + }, + { + "name": "PHI4_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + } + ] }, - "throughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + "publicNetworkAccess": { + "value": "Enabled" } }, "template": { @@ -54892,1212 +59436,722 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11959636451300474346" + "version": "0.37.4.10188", + "templateHash": "396653159019145335" }, - "name": "DocumentDB Database Account Gremlin Databases", - "description": "This module deploys a Gremlin Database within a CosmosDB Account." + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." }, "definitions": { - "graphType": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the graph." + "description": "The name of the private endpoint." } }, - "tags": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true + "description": "The resource ID of the private endpoint." + } }, - "indexingPolicy": { - "type": "object", + "groupId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true + "description": "The group Id for the private endpoint Group." + } }, - "partitionKeyPaths": { + "customDnsConfigs": { "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "nullable": true + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a graph." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." + "__bicep_export!": true } }, - "tags": { + "replicaLocationType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } }, - "description": "Optional. Tags of the Gremlin database resource." + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", "metadata": { - "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for a replica location" } }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" }, - "gremlinDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } } }, - "dependsOn": [ - "databaseAccount" - ] + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "gremlinDatabase_gremlinGraphs": { - "copy": { - "name": "gremlinDatabase_gremlinGraphs", - "count": "[length(coalesce(parameters('graphs'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "_1.privateEndpointIpConfigurationType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" - }, - "gremlinDatabaseName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" - }, - "partitionKeyPaths": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10487122333182352122" - }, - "name": "DocumentDB Database Accounts Gremlin Databases Graphs", - "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." - }, - "parameters": { - "name": { + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "Required. Name of the graph." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "databaseAccountName": { + "memberName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." } }, - "gremlinDatabaseName": { + "privateIPAddress": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true } }, - "resources": { - "databaseAccount::gremlinDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "gremlinGraph": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "indexingPolicy": "[parameters('indexingPolicy')]", - "partitionKey": { - "paths": "[parameters('partitionKeyPaths')]" - } + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." } } } }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the graph." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the graph." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the graph was created in." - }, - "value": "[resourceGroup().name]" - } + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } }, - "dependsOn": [ - "gremlinDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Gremlin database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Gremlin database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Gremlin database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_tables": { - "copy": { - "name": "databaseAccount_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1787500858429182824" - }, - "name": "Azure Cosmos DB account tables", - "description": "This module deploys a table within an Azure Cosmos DB Account." - }, - "parameters": { - "name": { - "type": "string", "metadata": { - "description": "Required. Name of the table." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "tags": { + "_1.roleAssignmentType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } }, - "description": "Optional. Tags for the table." + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" }, - "table": { - "type": "Microsoft.DocumentDB/databaseAccounts/tables", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "customerManagedKeyWithAutoRotateType": { + "type": "object", "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } } }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraKeyspaces": { - "copy": { - "name": "databaseAccount_cassandraKeyspaces", - "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "tables": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" - }, - "views": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15257396763463366586" + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "name": "DocumentDB Database Account Cassandra Keyspaces", - "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." - }, - "definitions": { - "tableType": { + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the table." + "description": "Optional. The name of the diagnostic setting." } }, - "schema": { - "type": "object", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the table." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the table." + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } }, - "defaultTtl": { - "type": "int", + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], "nullable": true, "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "analyticalStorageTtl": { - "type": "int", + "workspaceResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Analytical TTL for the table." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "throughput": { - "type": "int", + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra table." + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } }, - "viewType": { + "privateEndpointSingleServiceType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the view." + "description": "Optional. The name of the Private Endpoint." } }, - "viewDefinition": { + "location": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. View definition (CQL statement)." + "description": "Optional. The location to deploy the Private Endpoint to." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags for the view." - }, - "nullable": true - }, - "throughput": { - "type": "int", + "privateLinkServiceConnectionName": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "description": "Optional. The name of the private link connection to create." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "service": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra view (materialized view)." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra keyspace." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra keyspace resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." - } - }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/viewType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraKeyspace": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "cassandraKeyspace_tables": { - "copy": { - "name": "cassandraKeyspace_tables", - "count": "[length(parameters('tables'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('tables')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "schema": { - "value": "[parameters('tables')[copyIndex()].schema]" - }, - "analyticalStorageTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" - }, - "throughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "defaultTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "resourceGroupResourceId": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15998065591386988132" - }, - "name": "DocumentDB Database Account Cassandra Keyspaces Tables", - "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra table resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "cassandraKeyspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." - } - }, - "schema": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the Cassandra table." - } - }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." - } - }, - "defaultTtl": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." - } - } - }, - "resources": { - "databaseAccount::cassandraKeyspace": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraTable": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "schema": "[parameters('schema')]", - "defaultTtl": "[parameters('defaultTtl')]", - "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra table was created in." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." } - } - }, - "dependsOn": [ - "cassandraKeyspace" - ] - }, - "cassandraKeyspace_views": { - "copy": { - "name": "cassandraKeyspace_views", - "count": "[length(parameters('views'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('views')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "viewDefinition": { - "value": "[parameters('views')[copyIndex()].viewDefinition]" - }, - "throughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "isManualConnection": { + "type": "bool", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "6617803098467821091" - }, - "name": "DocumentDB Database Account Cassandra Keyspaces Views", - "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra view." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags of the Cassandra view resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "cassandraKeyspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." - } - }, - "viewDefinition": { - "type": "string", - "metadata": { - "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - } - }, - "resources": { - "databaseAccount::cassandraKeyspace": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-05-01-preview", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraView": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "viewDefinition": "[parameters('viewDefinition')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra view." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra view." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra view was created in." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. If Manual Private Link Connection is required." } - } - }, - "dependsOn": [ - "cassandraKeyspace" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra keyspace." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra keyspace." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra keyspace was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_privateEndpoints": { - "copy": { - "name": "databaseAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { + }, + "manualConnectionRequestMessage": { "type": "string", "nullable": true, + "maxLength": 140, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "privateDnsZoneGroupConfigs": { + "customDnsConfigs": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Custom DNS configurations." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." } }, - "kind": { + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", "nullable": true, "metadata": { "description": "Optional. Specify the type of lock." } }, - "notes": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. Array of role assignments to create." } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." } }, - "privateDnsZoneResourceId": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "description": "The type of a private DNS zone group configuration.", + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -56172,7 +60226,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } @@ -56181,54 +60235,113 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Azure App Configuration." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all Resources." } }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. The managed identity definition for this resource." } }, - "customNetworkInterfaceName": { + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { "type": "string", "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." } }, - "ipConfigurations": { + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { "type": "array", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, "nullable": true, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. All Replicas to create." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. The diagnostic settings of the service." } }, "lock": { @@ -56252,41 +60365,18 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. Tags of the resource." }, "nullable": true }, - "privateLinkServiceConnections": { - "type": "array", + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } }, "enableTelemetry": { "type": "bool", @@ -56294,6 +60384,16 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } } }, "variables": { @@ -56304,25 +60404,38 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -56338,55 +60451,112 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] }, - "privateEndpoint_lock": { + "configurationStore_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "configurationStore" ] }, - "privateEndpoint_roleAssignments": { + "configurationStore_diagnosticSettings": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -56397,28 +60567,284 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "configurationStore" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" }, - "privateEndpointName": { + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -56428,13 +60854,175 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { "privateDnsZoneGroupConfigType": { "type": "object", "properties": { @@ -56453,1897 +61041,2836 @@ } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } } }, "parameters": { - "privateEndpointName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "privateDnsZoneConfigs": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "type": "string" }, - "minLength": 1, - "maxLength": 5, + "nullable": true, "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "name": { + "customNetworkInterfaceName": { "type": "string", - "defaultValue": "default", + "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, "privateEndpoint": { - "existing": true, "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" } } - ] - } + } + }, + "dependsOn": [ + "privateEndpoint" + ] } }, "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the private endpoint." }, "value": "[parameters('name')]" }, - "resourceId": { + "location": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The location the resource was deployed into." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" }, - "resourceGroupName": { + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The group Id for the private endpoint Group." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } }, "dependsOn": [ - "privateEndpoint" + "configurationStore" ] } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." + "description": "The name of the app configuration." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "The resource ID of the app configuration." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The resource group the app configuration store was deployed into." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" }, - "customDnsConfigs": { - "type": "array", + "endpoint": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." + "description": "The endpoint of the app configuration." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[reference('configurationStore').endpoint]" }, - "networkInterfaceResourceIds": { + "privateEndpoints": { "type": "array", "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "$ref": "#/definitions/privateEndpointOutputType" }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The private endpoints of the app configuration." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } }, "dependsOn": [ - "databaseAccount" + "avmAiServices", + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Web", + "avmContainerApp_Workflow", + "avmCosmosDB", + "avmStorageAccount", + "logAnalyticsWorkspace" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the database account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the database account." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the database account was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the database account." - }, - "value": "[reference('databaseAccount').documentEndpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the database account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "primaryReadWriteKey": { - "type": "securestring", - "metadata": { - "description": "The primary read-write key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" - }, - "primaryReadOnlyKey": { - "type": "securestring", - "metadata": { - "description": "The primary read-only key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" - }, - "primaryReadWriteConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary read-write connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" - }, - "primaryReadOnlyConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary read-only connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" - }, - "secondaryReadWriteKey": { - "type": "securestring", - "metadata": { - "description": "The secondary read-write key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" - }, - "secondaryReadOnlyKey": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" - }, - "secondaryReadWriteConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary read-write connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" - }, - "secondaryReadOnlyConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" - } - } - } - }, - "dependsOn": [ - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", - "virtualNetwork" - ] - }, - "avmAppConfig": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('location')]" - } - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "sku": { - "value": "Standard" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "disableLocalAuth": { - "value": false - }, - "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - } - ] - }, - "keyValues": { - "value": [ - { - "name": "APP_AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_AZURE_OPENAI_MODEL", - "value": "[parameters('gptModelName')]" - }, - { - "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_COSMOS_CONTAINER_PROCESS", - "value": "Processes" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMA", - "value": "Schemas" - }, - { - "name": "APP_COSMOS_DATABASE", - "value": "ContentProcess" - }, - { - "name": "APP_CPS_CONFIGURATION", - "value": "cps-configuration" - }, - { - "name": "APP_CPS_MAX_FILESIZE_MB", - "value": "20" - }, - { - "name": "APP_CPS_PROCESSES", - "value": "cps-processes" - }, - { - "name": "APP_MESSAGE_QUEUE_EXTRACT", - "value": "content-pipeline-extract-queue" - }, - { - "name": "APP_MESSAGE_QUEUE_INTERVAL", - "value": "5" - }, - { - "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", - "value": "180" - }, - { - "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", - "value": "10" - }, - { - "name": "APP_PROCESS_STEPS", - "value": "extract,map,evaluate,save" - }, - { - "name": "APP_STORAGE_BLOB_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" - }, - { - "name": "APP_STORAGE_QUEUE_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" - }, - { - "name": "APP_AI_PROJECT_ENDPOINT", - "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" - }, - { - "name": "APP_COSMOS_CONNSTR", - "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", - "value": "claimprocesses" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCHES", - "value": "batches" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMASET", - "value": "Schemasets" - }, - { - "name": "APP_CPS_PROCESS_BATCH", - "value": "process-batch" - }, - { - "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", - "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" - }, - { - "name": "APP_CPS_POLL_INTERVAL_SECONDS", - "value": "3" - }, - { - "name": "APP_STORAGE_ACCOUNT_NAME", - "value": "[reference('avmStorageAccount').outputs.name.value]" - }, - { - "name": "CLAIM_PROCESS_QUEUE_NAME", - "value": "claim-process-queue" - }, - { - "name": "DEAD_LETTER_QUEUE_NAME", - "value": "claim-process-dead-letter-queue" - }, - { - "name": "AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", - "value": "[parameters('gptModelName')]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "AZURE_OPENAI_ENDPOINT_BASE", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", - "value": "" - }, - { - "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", - "value": "" - }, - { - "name": "AZURE_TRACING_ENABLED", - "value": "True" - }, - { - "name": "GLOBAL_LLM_SERVICE", - "value": "AzureOpenAI" - }, - { - "name": "GPT5_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "GPT5_CHAT_DEPLOYMENT_NAME", - "value": "gpt-5" - }, - { - "name": "GPT5_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "PHI4_API_VERSION", - "value": "2024-05-01-preview" - }, - { - "name": "PHI4_CHAT_DEPLOYMENT_NAME", - "value": "phi-4" - }, - { - "name": "PHI4_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - } - ] - }, - "publicNetworkAccess": { - "value": "Enabled" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } }, - "privateEndpointOutputType": { - "type": "object", + "avmAppConfig_update": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "privateEndpoints": { + "value": [ + { + "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", + "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "name": "appconfig-dns-zone-group", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" + } + ] + }, + "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + ] } }, - "groupId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "memberName": { - "type": "string", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "privateIPAddress": { - "type": "string", + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure App Configuration." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], - "metadata": { - "description": "Optional. Pricing tier of App Configuration." - } - }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], - "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "keyValues": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." - } - }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All Replicas to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, - "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" - }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the key." + "description": "Required. Name of the Azure App Configuration." } }, - "value": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], "metadata": { - "description": "Required. The value of the key-value." + "description": "Optional. Pricing tier of App Configuration." } }, - "appConfigurationName": { + "createMode": { "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." } }, - "contentType": { + "publicNetworkAccess": { "type": "string", "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", - "nullable": true, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "appConfiguration": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { "type": "Microsoft.AppConfiguration/configurationStores", "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" - } + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the key values." + "description": "The name of the app configuration." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the key values." + "description": "The resource ID of the app configuration." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the batch account was deployed into." + "description": "The resource group the app configuration store was deployed into." }, "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" - }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", - "metadata": { - "description": "Optional. Name of the replica." - } }, - "appConfigurationName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - } - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The resource group the app configuration was deployed into." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" }, - "name": { + "endpoint": { "type": "string", "metadata": { - "description": "The name of the replica that was deployed." + "description": "The endpoint of the app configuration." }, - "value": "[parameters('name')]" + "value": "[reference('configurationStore').endpoint]" }, - "resourceId": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "The resource ID of the replica that was deployed." + "description": "The private endpoints of the app configuration." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } }, "dependsOn": [ - "configurationStore" + "avmAppConfig", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", + "virtualNetwork" ] }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, + "avmContainerApp_update": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -58351,42 +63878,91 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "location": { + "value": "[parameters('location')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "value": "[parameters('enableTelemetry')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "workloadProfileName": { + "value": "Consumption" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "registries": { + "value": null }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "value": "[parameters('tags')]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "activeRevisionsMode": { + "value": "Single" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "ingressExternal": { + "value": false }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" + } } }, "template": { @@ -58396,143 +63972,636 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { + "scaleType": { "type": "object", "properties": { - "name": { - "type": "string", + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. The cooldown period in seconds." } }, - "privateDnsZoneGroupConfigs": { + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/scaleRuleType" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The scaling rules." } } }, "metadata": { - "__bicep_export!": true + "description": "The scale settings for the Container App." } }, - "ipConfigurationType": { + "scaleRuleType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. The name of the scaling rule." } }, - "properties": { + "custom": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." } } }, "metadata": { - "__bicep_export!": true + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." } }, - "privateLinkServiceConnectionType": { + "secretType": { "type": "object", "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. The name of the container app secret." } }, - "properties": { + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." }, + "nullable": true + }, + "httpSettings": { + "type": "object", "metadata": { - "description": "Required. Properties of private link service connection." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." } }, - "customDnsConfigType": { + "diagnosticSettingMetricsOnlyType": { "type": "object", "properties": { - "fqdn": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. The name of diagnostic setting." } }, - "ipAddresses": { + "metricCategories": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } }, + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, "lockType": { @@ -58556,35 +64625,47 @@ "metadata": { "description": "Optional. Specify the type of lock." } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "privateDnsZoneGroupConfigType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "privateDnsZoneResourceId": { - "type": "string", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -58659,7 +64740,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -58668,54 +64749,161 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Container App." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all Resources." } }, - "applicationSecurityGroupResourceIds": { + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/ingressPortMappingType" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. Settings to expose additional ports on container app." } }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } }, - "ipConfigurations": { + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { "type": "array", "items": { - "$ref": "#/definitions/ipConfigurationType" + "$ref": "#/definitions/serviceBindingType" }, "nullable": true, "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. List of container app services bound to the app." } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. Controls how active revisions are handled for the Container app." } }, - "location": { + "environmentResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Required. Resource ID of environment." } }, "lock": { @@ -58725,6 +64913,33 @@ "description": "Optional. The lock settings of the service." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "roleAssignments": { "type": "array", "items": { @@ -58735,48 +64950,162 @@ "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDnsConfigs": { + "customDomains": { "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Optional. The termination grace period for the container app." } }, - "manualPrivateLinkServiceConnections": { + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { "type": "array", "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "$ref": "#/definitions/secretType" }, "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. The secrets of the Container App." } }, - "privateLinkServiceConnections": { + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. Workload profile name to pin for container app execution." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, @@ -58788,25 +65117,24 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -58822,55 +65150,62 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", "name": "[parameters('name')]", - "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" } } }, - "privateEndpoint_lock": { + "containerApp_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_roleAssignments": { + "containerApp_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "containerApp_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -58881,28 +65216,75 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "containerAppName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" } }, "template": { @@ -58912,88 +65294,125 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." }, - "definitions": { - "privateDnsZoneGroupConfigType": { + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." }, + "nullable": true + }, + "globalValidation": { + "type": "object", "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." }, - "minLength": 1, - "maxLength": 5, + "nullable": true + }, + "login": { + "type": "object", "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "name": { - "type": "string", - "defaultValue": "default", + "platform": { + "type": "object", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" } } }, @@ -59001,21 +65420,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the set of Container App Auth configs." }, - "value": "[parameters('name')]" + "value": "current" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the set of Container App Auth configs." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The resource group containing the set of Container App Auth configs." }, "value": "[resourceGroup().name]" } @@ -59023,1572 +65442,1769 @@ } }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" + ] + }, + "avmContainerApp_API_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "description": "The type for a container app probe HTTP GET." + } }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "description": "The type for a container app probe HTTP GET header." + } }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } }, "metadata": { - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "description": "The type for a container app probe TCP socket." + } }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } }, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "description": "The scale settings for the Container App." + } }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the app configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the app configuration." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration store was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the app configuration." - }, - "value": "[reference('configurationStore').endpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the app configuration." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "avmAiServices", - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Web", - "avmContainerApp_Workflow", - "avmCosmosDB", - "avmStorageAccount", - "logAnalyticsWorkspace" - ] - }, - "avmAppConfig_update": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "publicNetworkAccess": { - "value": "Disabled" - }, - "privateEndpoints": { - "value": [ - { - "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", - "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", - "privateDnsZoneGroup": { - "privateDnsZoneGroupConfigs": [ - { - "name": "appconfig-dns-zone-group", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" - } - ] - }, - "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } - }, - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "The scaling rules for the Container App." } }, - "memberName": { - "type": "string", + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "The type for a volume mount." } }, - "privateIPAddress": { - "type": "string", + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "__bicep_export!": true, + "description": "The type for a secret." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure App Configuration." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], - "metadata": { - "description": "Optional. Pricing tier of App Configuration." - } - }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], - "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "keyValues": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." - } - }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All Replicas to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, - "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" - }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the key." + "description": "Required. Name of the Container App." } }, - "value": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The value of the key-value." + "description": "Optional. Location for all Resources." } }, - "appConfigurationName": { + "kind": { "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." } }, - "contentType": { + "clientCertificateMode": { "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", "nullable": true, "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "description": "Optional. Object userd to configure CORS policy." } }, - "tags": { + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Settings to expose additional ports on container app." } - } - }, - "resources": { - "appConfiguration": { - "existing": true, - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } - } - }, - "outputs": { - "name": { + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { "type": "string", "metadata": { - "description": "The name of the key values." + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." }, - "value": "[parameters('name')]" + "nullable": true }, - "resourceId": { + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", "metadata": { - "description": "The resource ID of the key values." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + "nullable": true }, - "resourceGroupName": { + "workloadProfileName": { "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, "metadata": { - "description": "The resource group the batch account was deployed into." + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, - "value": "[resourceGroup().name]" + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } }, - "parameters": { - "name": { + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", "metadata": { - "description": "Optional. Name of the replica." - } + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "appConfigurationName": { + "fqdn": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - } - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the app configuration was deployed into." + "description": "The name of the resource group the Container App was deployed into." }, "value": "[resourceGroup().name]" }, "name": { "type": "string", "metadata": { - "description": "The name of the replica that was deployed." + "description": "The name of the Container App." }, "value": "[parameters('name')]" }, - "resourceId": { + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { "type": "string", "metadata": { - "description": "The resource ID of the replica that was deployed." + "description": "The location the resource was deployed into." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } }, "dependsOn": [ - "configurationStore" + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" ] }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, + "avmContainerApp_Workflow_update": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -60596,42 +67212,90 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "location": { + "value": "[parameters('location')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "value": "[parameters('enableTelemetry')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "workloadProfileName": { + "value": "Consumption" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "registries": { + "value": null }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "activeRevisionsMode": { + "value": "Single" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "ingressExternal": { + "value": false }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "disableIngress": { + "value": true }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } } }, "template": { @@ -60641,143 +67305,636 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Container Apps", + "description": "This module deploys a Container App." }, "definitions": { - "privateDnsZoneGroupType": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { "type": "object", "properties": { "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." } }, - "privateDnsZoneGroupConfigs": { + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "type": "string" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type for a CORS policy." } }, - "ipConfigurationType": { + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. Name of the header." } }, - "properties": { + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { + }, + "workspaceResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. Properties of private link service connection." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { + }, + "eventHubAuthorizationRuleResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, + "eventHubName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, "lockType": { @@ -60801,35 +67958,47 @@ "metadata": { "description": "Optional. Specify the type of lock." } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "privateDnsZoneGroupConfigType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "privateDnsZoneResourceId": { - "type": "string", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -60904,7 +68073,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -60913,54 +68082,161 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Container App." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all Resources." } }, - "applicationSecurityGroupResourceIds": { + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/ingressPortMappingType" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. Settings to expose additional ports on container app." } }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } }, - "ipConfigurations": { + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { "type": "array", "items": { - "$ref": "#/definitions/ipConfigurationType" + "$ref": "#/definitions/serviceBindingType" }, "nullable": true, "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. List of container app services bound to the app." } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. Controls how active revisions are handled for the Container app." } }, - "location": { + "environmentResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Required. Resource ID of environment." } }, "lock": { @@ -60970,6 +68246,33 @@ "description": "Optional. The lock settings of the service." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "roleAssignments": { "type": "array", "items": { @@ -60980,48 +68283,162 @@ "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDnsConfigs": { + "customDomains": { "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Optional. The termination grace period for the container app." } }, - "manualPrivateLinkServiceConnections": { + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { "type": "array", "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "$ref": "#/definitions/secretType" }, "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. The secrets of the Container App." } }, - "privateLinkServiceConnections": { + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. Workload profile name to pin for container app execution." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, @@ -61033,25 +68450,24 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -61067,55 +68483,62 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", "name": "[parameters('name')]", - "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" } } }, - "privateEndpoint_lock": { + "containerApp_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_roleAssignments": { + "containerApp_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "containerApp_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -61126,28 +68549,75 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "containerAppName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" } }, "template": { @@ -61157,88 +68627,125 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." }, - "definitions": { - "privateDnsZoneGroupConfigType": { + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." }, + "nullable": true + }, + "httpSettings": { + "type": "object", "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." }, - "minLength": 1, - "maxLength": 5, + "nullable": true + }, + "platform": { + "type": "object", "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "name": { - "type": "string", - "defaultValue": "default", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" } } }, @@ -61246,21 +68753,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the set of Container App Auth configs." }, - "value": "[parameters('name')]" + "value": "current" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the set of Container App Auth configs." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The resource group containing the set of Container App Auth configs." }, "value": "[resourceGroup().name]" } @@ -61268,4898 +68775,3347 @@ } }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "The resource ID of the Container App." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The configuration of ingress fqdn." }, - "value": "[parameters('name')]" + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "location": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The name of the resource group the Container App was deployed into." }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "value": "[resourceGroup().name]" }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, + "name": { + "type": "string", "metadata": { - "description": "The custom DNS configurations of the private endpoint." + "description": "The name of the Container App." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[parameters('name')]" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The principal ID of the system assigned identity." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" }, - "groupId": { + "location": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The location the resource was deployed into." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } }, "dependsOn": [ - "configurationStore" + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] } }, "outputs": { - "name": { + "CONTAINER_WEB_APP_NAME": { "type": "string", "metadata": { - "description": "The name of the app configuration." + "description": "The name of the Container App used for Web App." }, - "value": "[parameters('name')]" + "value": "[reference('avmContainerApp_Web').outputs.name.value]" }, - "resourceId": { + "CONTAINER_API_APP_NAME": { "type": "string", "metadata": { - "description": "The resource ID of the app configuration." + "description": "The name of the Container App used for API." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + "value": "[reference('avmContainerApp_API').outputs.name.value]" }, - "resourceGroupName": { + "CONTAINER_WEB_APP_FQDN": { "type": "string", "metadata": { - "description": "The resource group the app configuration store was deployed into." + "description": "The FQDN of the Container App." }, - "value": "[resourceGroup().name]" + "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" }, - "systemAssignedMIPrincipalId": { + "CONTAINER_API_APP_FQDN": { "type": "string", - "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "The FQDN of the Container App API." }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" }, - "location": { + "CONTAINER_APP_NAME": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The name of the Container App used for APP." }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" + "value": "[reference('avmContainerApp').outputs.name.value]" }, - "endpoint": { + "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", "metadata": { - "description": "The endpoint of the app configuration." + "description": "The name of the Container App used for Workflow." }, - "value": "[reference('configurationStore').endpoint]" + "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "metadata": { + "description": "The user identity resource ID used fot the Container APP." }, + "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", "metadata": { - "description": "The private endpoints of the app configuration." + "description": "The user identity Principal ID used fot the Container APP." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } + "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "metadata": { + "description": "The login server of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "metadata": { + "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." + }, + "value": "[reference('avmAiServices').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "metadata": { + "description": "The resource group the resources were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "SOLUTION_NAME": { + "type": "string", + "metadata": { + "description": "The solution name." + }, + "value": "[parameters('solutionName')]" } } } - }, - "dependsOn": [ - "avmAppConfig", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", - "virtualNetwork" - ] + } }, - "avmContainerApp_update": { + { + "condition": "[variables('isBicep')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.bicep.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" + "solutionName": { + "value": "[parameters('solutionName')]" }, "location": { "value": "[parameters('location')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "azureAiServiceLocation": { + "value": "[parameters('azureAiServiceLocation')]" }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + "gptModelName": { + "value": "[parameters('gptModelName')]" }, - "workloadProfileName": { - "value": "Consumption" + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" }, - "registries": { - "value": null + "imageTag": { + "value": "[parameters('imageTag')]" }, - "tags": { - "value": "[parameters('tags')]" + "enablePrivateNetworking": { + "value": "[variables('effectiveEnablePrivateNetworking')]" }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } + "enableMonitoring": { + "value": "[variables('effectiveEnableMonitoring')]" }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } - ] + "enableRedundancy": { + "value": "[variables('effectiveEnableRedundancy')]" }, - "activeRevisionsMode": { - "value": "Single" + "enableScalability": { + "value": "[variables('effectiveEnableScalability')]" }, - "ingressExternal": { - "value": false + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "disableIngress": { - "value": true + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" - } + "tags": { + "value": "[parameters('tags')]" } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6422306545253132015" + }, + "name": "Content Processing Solution Accelerator - Bicep", + "description": "Deploys Content Processing resources using the restored private-repo module interfaces." }, "parameters": { - "name": { + "solutionName": { "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20 }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "azd": { + "type": "location" + } } }, - "kind": { + "azureAiServiceLocation": { "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + "azd": { + "type": "location" + } } }, - "clientCertificateMode": { + "gptModelName": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } + "defaultValue": "gpt-5.1" }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { + "containerRegistryEndpoint": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } + "defaultValue": "" }, - "ingressTransport": { + "imageTag": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } + "defaultValue": "latest_v2" }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false }, - "includeAddOns": { + "enableMonitoring": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } + "defaultValue": false }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } + "enableRedundancy": { + "type": "bool", + "defaultValue": false }, - "ingressAllowInsecure": { + "enableScalability": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } + "defaultValue": false }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } + "enableTelemetry": { + "type": "bool", + "defaultValue": true + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", + "tags": { + "type": "object", "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" + } + }, + "variables": { + "uniqueToken": "[substring(uniqueString(subscription().subscriptionId, resourceGroup().id, parameters('solutionName')), 0, 5)]", + "solutionSuffix": "[toLower(replace(replace(replace(format('{0}{1}', parameters('solutionName'), variables('uniqueToken')), '-', ''), '_', ''), '.', ''))]", + "managedIdentityName": "[format('id-{0}', variables('solutionSuffix'))]", + "containerRegistryName": "[replace(format('cr{0}', variables('solutionSuffix')), '-', '')]", + "storageAccountName": "[take(replace(format('st{0}', variables('solutionSuffix')), '-', ''), 24)]", + "cosmosDbName": "[format('cosmos-{0}', variables('solutionSuffix'))]", + "cosmosDatabaseName": "contentprocessing", + "cosmosContainerName": "documents", + "aiServicesName": "[format('aif-{0}', variables('solutionSuffix'))]", + "aiProjectName": "[format('proj-{0}', variables('solutionSuffix'))]", + "aiSearchName": "[format('srch-{0}', variables('solutionSuffix'))]", + "appConfigurationName": "[format('appcs-{0}', variables('solutionSuffix'))]", + "containerAppEnvironmentName": "[format('cae-{0}', variables('solutionSuffix'))]", + "contentProcessorAppName": "[format('ca-{0}-app', variables('solutionSuffix'))]", + "contentProcessorApiName": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "contentProcessorWebName": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "contentProcessorWorkflowName": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "modelDeploymentName": "[format('gpt-{0}', variables('solutionSuffix'))]", + "storageContainerName": "content", + "storageQueueName": "content", + "acrPullRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "storageBlobDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "storageQueueDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "appConfigurationDataReaderRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "cognitiveServicesOpenAiUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "cognitiveServicesUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "azureAiDeveloperRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "cosmosDbEndpoint": "[format('https://{0}.mongo.cosmos.azure.com:443/', variables('cosmosDbName'))]", + "apiProbes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 } + ] + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]" }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } + { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', variables('storageQueueName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageAccountName'), 'default')]" + ] }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." + { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2023-04-15", + "name": "[variables('cosmosDbName')]", + "location": "[parameters('location')]", + "kind": "MongoDB", + "tags": "[parameters('tags')]", + "properties": { + "databaseAccountOfferType": "Standard", + "locations": [ + { + "locationName": "[parameters('location')]", + "failoverPriority": 0, + "isZoneRedundant": "[parameters('enableRedundancy')]" + } + ], + "capabilities": [ + { + "name": "EnableMongo" + } + ], + "apiProperties": { + "serverVersion": "7.0" + }, + "disableLocalAuth": false, + "enableAutomaticFailover": false, + "enableMultipleWriteLocations": false, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]" } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}', variables('cosmosDbName'), variables('cosmosDatabaseName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosDatabaseName')]" }, - "description": "Optional. Tags of the resource." + "options": {} }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]" + ] }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}/{2}', variables('cosmosDbName'), variables('cosmosDatabaseName'), variables('cosmosContainerName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosContainerName')]", + "shardKey": { + "id": "Hash" + }, + "indexes": [ + { + "key": { + "keys": [ + "_id" + ] + } + } + ] }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + "options": {} }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', variables('cosmosDbName'), variables('cosmosDatabaseName'))]" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + { + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', variables('aiServicesName'), variables('aiProjectName'))]", + "location": "[parameters('azureAiServiceLocation')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "tags": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]", + "properties": {} }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', variables('containerRegistryName'))]", + "name": "[guid(variables('containerRegistryName'), variables('managedIdentityName'), 'acr-pull')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('acrPullRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorAppName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorApiName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWebName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64))]" + ] }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWorkflowName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7692694992043508018" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "metadata": { + "description": "SKU name for the workspace." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "retentionInDays": "[parameters('retentionInDays')]", + "sku": { + "name": "[parameters('skuName')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01', 'full').location]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01').customerId]" + } + } + } } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + { + "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "workspaceResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4667471246975862151" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('appi-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace to link to." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Application type." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable IP masking for security." + } + }, + "flowType": { + "type": "string", + "defaultValue": "Bluefield", + "metadata": { + "description": "Flow type for Application Insights." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "web", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "Flow_Type": "[parameters('flowType')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "publicNetworkAccessForIngestion": "Enabled", + "publicNetworkAccessForQuery": "Enabled" + } + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Application Insights instance." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Application Insights instance." + }, + "value": "[parameters('name')]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Instrumentation key for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Connection string for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').ConnectionString]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "Application ID of the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').AppId]" } } } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "identityName": { + "value": "[variables('managedIdentityName')]" }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "location": { + "value": "[parameters('location')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "14165903959794426055" + } }, "parameters": { - "containerAppName": { + "solutionName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Solution name used for resource naming." } }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Name of the managed identity." + } }, - "login": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "platform": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Tags to apply to the resource." } } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" } - }, + ], "outputs": { - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "Resource ID of the managed identity." }, - "value": "current" + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]" }, - "resourceId": { + "principalId": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Principal ID (object ID) of the managed identity." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').principalId]" }, - "resourceGroupName": { + "clientId": { "type": "string", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "Client ID of the managed identity." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" - ] - }, - "avmContainerApp_API_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 - } - ] - } - ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').clientId]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[parameters('identityName')]" } } } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." } }, - "corsPolicyType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" + "name": { + "value": "[variables('containerRegistryName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." + "sku": "[if(parameters('enableRedundancy'), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" } }, - "pollingInterval": { - "type": "int", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17432455227529690473" + } }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "adminUserEnabled": "[parameters('adminUserEnabled')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "dataEndpointEnabled": false, + "networkRuleBypassOptions": "AzureServices", + "policies": { + "exportPolicy": { + "status": "[parameters('exportPolicyStatus')]" + }, + "retentionPolicy": { + "status": "enabled", + "days": 7 + }, + "trustPolicy": { + "status": "disabled", + "type": "Notary" + } + }, + "zoneRedundancy": "Disabled" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + } } } - }, - "metadata": { - "description": "The type for a volume mount." } }, - "secretType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": "[if(parameters('enableRedundancy'), createObject('value', 'Standard_ZRS'), createObject('value', 'Standard_LRS'))]", + "containers": { + "value": [ + { + "name": "[variables('storageContainerName')]", + "publicAccess": "None" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" } }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17696053432794478605" + } }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "name": { + "type": "string", + "defaultValue": "[take(format('st{0}', toLower(replace(parameters('solutionName'), '-', ''))), 24)]", + "metadata": { + "description": "Name of the storage account." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "skuName": { + "type": "string", + "defaultValue": "Standard_LRS", + "metadata": { + "description": "Storage account SKU." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "metadata": { + "description": "Storage account kind." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Hot", + "Cool" + ], + "metadata": { + "description": "Access tier." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Allow blob public access." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Allow shared key access." + } + }, + "containers": { + "type": "array", + "defaultValue": [ + { + "name": "default", + "publicAccess": "None" } + ], + "metadata": { + "description": "Blob containers to create." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "properties": { + "accessTier": "[parameters('accessTier')]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "minimumTlsVersion": "TLS1_2", + "supportsHttpsTrafficOnly": true, + "encryption": { + "services": { + "blob": { + "enabled": true + }, + "file": { + "enabled": true + } + }, + "keySource": "Microsoft.Storage", + "requireInfrastructureEncryption": true } } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "blobContainers", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', parameters('containers')[copyIndex()].name)]", + "properties": { + "publicAccess": "[parameters('containers')[copyIndex()].publicAccess]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('name'), 'default')]" + ] } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Storage Account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Storage Account." + }, + "value": "[parameters('name')]" + }, + "blobEndpoint": { + "type": "string", + "metadata": { + "description": "Primary blob endpoint." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.blob]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } }, - "managedIdentityAllType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)]", "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('aiServicesName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "principalIds": { + "value": [] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7594344478012985364" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services account." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Required. Azure region for the resource." + } + }, + "principalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether public network access is allowed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to apply to the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "sku": { + "name": "S0" + }, + "properties": { + "customSubDomainName": "[parameters('name')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "disableLocalAuth": true, + "allowProjectManagement": true, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" + } + } + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principalIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", + "properties": { + "principalId": "[parameters('principalIds')[copyIndex()]]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AI Services account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the AI Services account." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the AI Services account." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01').endpoint]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01', 'full').identity.principalId]" + } + } + } } }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-model.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + "mode": "Incremental", + "parameters": { + "aiServicesAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "deploymentName": { + "value": "[variables('modelDeploymentName')]" + }, + "modelName": { + "value": "[parameters('gptModelName')]" + }, + "skuName": { + "value": "GlobalStandard" + }, + "skuCapacity": { + "value": 10 + } }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18411757618261752815" + } + }, + "parameters": { + "aiServicesAccountName": { + "type": "string", + "metadata": { + "description": "Required. Name of the parent AI Services account." + } + }, + "deploymentName": { + "type": "string", + "metadata": { + "description": "Required. Name for this model deployment." + } + }, + "modelFormat": { + "type": "string", + "defaultValue": "OpenAI", + "metadata": { + "description": "Optional. Model format (e.g., OpenAI)." + } + }, + "modelName": { + "type": "string", + "metadata": { + "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." + } + }, + "modelVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Model version. Empty string means latest." + } + }, + "raiPolicyName": { + "type": "string", + "defaultValue": "Microsoft.Default", + "metadata": { + "description": "Optional. RAI policy name." + } + }, + "skuName": { + "type": "string", + "metadata": { + "description": "Required. SKU name (e.g., Standard, GlobalStandard)." + } + }, + "skuCapacity": { + "type": "int", + "metadata": { + "description": "Required. SKU capacity (tokens per minute in thousands)." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", + "properties": { + "model": { + "format": "[parameters('modelFormat')]", + "name": "[parameters('modelName')]", + "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" + }, + "raiPolicyName": "[parameters('raiPolicyName')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacity": "[parameters('skuCapacity')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the deployed model." + }, + "value": "[parameters('deploymentName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the model deployment." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]" + ] }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('aiSearchName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "714050788324647491" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "searchServiceUpdate", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "managedIdentityType": { + "value": "[parameters('managedIdentityType')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3683977219901178221" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the existing AI Search service." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The Azure region of the search service." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": { + "type": "[parameters('managedIdentityType')]" + }, + "properties": { + "replicaCount": "[parameters('replicaCount')]", + "partitionCount": "[parameters('partitionCount')]", + "hostingMode": "[parameters('hostingMode')]", + "semanticSearch": "[parameters('semanticSearch')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + } + } + ], + "outputs": { + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the AI Search system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.Search/searchServices', parameters('name')), '2025-05-01', 'full').identity.principalId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + ] + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." + }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'searchServiceUpdate'), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]" } } } } }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" + "expressionEvaluationOptions": { + "scope": "inner" }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('containerAppEnvironmentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17265155980354931238" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the Container Apps Environment." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + } + }, + "infrastructureSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for VNet integration (optional)." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable zone redundancy." + } + } + }, + "resources": [ + { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "appLogsConfiguration": { + "destination": "log-analytics", + "logAnalyticsConfiguration": { + "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", + "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" + } + }, + "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", + "zoneRedundant": "[parameters('zoneRedundant')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container Apps Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container Apps Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The default domain of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The static IP address of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.app-config.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "name": { + "value": "[variables('appConfigurationName')]" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "location": { + "value": "[parameters('location')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName')), '2025-12-01').endpoints['AI Foundry API']]" + }, + { + "name": "APP_COSMOS_DB_ENDPOINT", + "value": "[variables('cosmosDbEndpoint')]" + }, + { + "name": "APP_COSMOS_DB_NAME", + "value": "[variables('cosmosDatabaseName')]" + }, + { + "name": "APP_COSMOS_DB_CONTAINER", + "value": "[variables('cosmosContainerName')]" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "APP_STORAGE_BLOB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.blobEndpoint.value]" + }, + { + "name": "APP_STORAGE_QUEUE_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_STORAGE_CONTAINER_NAME", + "value": "[variables('storageContainerName')]" + }, + { + "name": "APP_AI_SEARCH_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_SEARCH_INDEX", + "value": "content-index" + }, + { + "name": "APP_WORKFLOW_APP_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "APP_API_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + } + ] }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "18286182317157861590" + } }, "parameters": { - "containerAppName": { + "solutionName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Solution name used for naming convention." } }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", + "name": { + "type": "string", + "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Name of the App Configuration store." + } }, - "identityProviders": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "login": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "platform": { - "type": "object", + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Standard" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "SKU for the configuration store." + } }, - "enableTelemetry": { + "disableLocalAuth": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Disable local (key-based) authentication." + } + }, + "keyValues": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Key-value pairs to store in the configuration." } } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2023-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "Enabled" } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + { + "copy": { + "name": "configurationKeyValues", + "count": "[length(parameters('keyValues'))]" + }, + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } + "value": "[parameters('keyValues')[copyIndex()].value]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + ] } - }, + ], "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "The name of the App Configuration store." }, - "value": "current" + "value": "[parameters('name')]" }, - "resourceId": { + "endpoint": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "The endpoint of the App Configuration store." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "The resource ID of the App Configuration store." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" } } } }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]" ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" - ] - }, - "avmContainerApp_Workflow_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-app.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorAppName')]" }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" + "location": { + "value": "[parameters('location')]" }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" + "disableIngress": { + "value": true }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" + "containers": { + "value": [ + { + "name": "[variables('contentProcessorAppName')]", + "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" + } + ] }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + "scaleSettings": { + "value": { + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]" + } }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." + "tags": { + "value": "[parameters('tags')]" } }, - "pollingInterval": { - "type": "int", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] }, - "managedIdentityAllType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-api.{0}', variables('solutionSuffix')), 64)]", "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorApiName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorApiName')]", + "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", + "probes": "[variables('apiProbes')]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('module.content-web.{0}', variables('solutionSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorWebName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWebName')]", + "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "*" + ] + } + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" } } } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[variables('contentProcessorWorkflowName')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "ingressExternal": { + "value": true }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWorkflowName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" + } + ] }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -66170,296 +72126,322 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "7554792250803110495" + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Name of the container app." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for deployment." + } }, - "globalValidation": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Resource tags." + } }, - "httpSettings": { - "type": "object", + "environmentResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Resource ID of the Container Apps Environment." + } }, - "identityProviders": { - "type": "object", + "containers": { + "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } }, - "login": { + "managedIdentities": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Managed identity configuration." + } }, - "platform": { + "corsPolicy": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 }, - "nullable": true + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "workloadProfileName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Workload profile name." } } }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", "properties": { - "mode": "Incremental", + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" } } } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "The name of the container app." }, - "value": "current" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "The resource ID of the container app." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "resourceGroupName": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "The FQDN of the container app." }, - "value": "[resourceGroup().name]" + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" } } } }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" ] } - }, + ], "outputs": { - "resourceId": { + "SOLUTION_NAME": { "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + "value": "[parameters('solutionName')]" }, - "fqdn": { + "CONTAINER_WEB_APP_NAME": { "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, - "resourceGroupName": { + "CONTAINER_API_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, - "name": { + "CONTAINER_WEB_APP_FQDN": { "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" + "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, - "systemAssignedMIPrincipalId": { + "CONTAINER_API_APP_FQDN": { "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, - "location": { + "CONTAINER_APP_NAME": { "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_WORKFLOW_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[resourceGroup().name]" } } } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] + } } - }, + ], "outputs": { + "SOLUTION_NAME": { + "type": "string", + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.SOLUTION_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.SOLUTION_NAME.value)]" + }, "CONTAINER_WEB_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for Web App." - }, - "value": "[reference('avmContainerApp_Web').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_NAME.value)]" }, "CONTAINER_API_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for API." - }, - "value": "[reference('avmContainerApp_API').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_NAME.value)]" }, "CONTAINER_WEB_APP_FQDN": { "type": "string", - "metadata": { - "description": "The FQDN of the Container App." - }, - "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_FQDN.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_FQDN.value)]" }, "CONTAINER_API_APP_FQDN": { "type": "string", - "metadata": { - "description": "The FQDN of the Container App API." - }, - "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_FQDN.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_FQDN.value)]" }, "CONTAINER_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for APP." - }, - "value": "[reference('avmContainerApp').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_NAME.value)]" }, "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for Workflow." - }, - "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WORKFLOW_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WORKFLOW_APP_NAME.value)]" }, "CONTAINER_APP_USER_IDENTITY_ID": { "type": "string", - "metadata": { - "description": "The user identity resource ID used fot the Container APP." - }, - "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_IDENTITY_ID.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_IDENTITY_ID.value)]" }, "CONTAINER_APP_USER_PRINCIPAL_ID": { "type": "string", - "metadata": { - "description": "The user identity Principal ID used fot the Container APP." - }, - "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value)]" }, "CONTAINER_REGISTRY_NAME": { "type": "string", - "metadata": { - "description": "The name of the Azure Container Registry." - }, - "value": "[reference('avmContainerRegistry').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_NAME.value)]" }, "CONTAINER_REGISTRY_LOGIN_SERVER": { "type": "string", - "metadata": { - "description": "The login server of the Azure Container Registry." - }, - "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value)]" }, "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { "type": "string", - "metadata": { - "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." - }, - "value": "[reference('avmAiServices').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value)]" }, "AZURE_RESOURCE_GROUP": { "type": "string", - "metadata": { - "description": "The resource group the resources were deployed into." - }, - "value": "[resourceGroup().name]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.AZURE_RESOURCE_GROUP.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.AZURE_RESOURCE_GROUP.value)]" } } } \ No newline at end of file diff --git a/infra/modules/account/aifoundry.bicep b/infra/modules/account/aifoundry.bicep deleted file mode 100644 index 4342f5f9..00000000 --- a/infra/modules/account/aifoundry.bicep +++ /dev/null @@ -1,421 +0,0 @@ -metadata name = 'Cognitive Services' -metadata description = 'This module deploys a Cognitive Service.' - -@description('Required. The name of Cognitive Services account.') -param name string - -@description('Optional: Name for the project which needs to be created.') -param projectName string - -@description('Optional: Description for the project which needs to be created.') -param projectDescription string - -param existingFoundryProjectResourceId string = '' - -@description('Required. Kind of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') -@allowed([ - 'AIServices' - 'AnomalyDetector' - 'CognitiveServices' - 'ComputerVision' - 'ContentModerator' - 'ContentSafety' - 'ConversationalLanguageUnderstanding' - 'CustomVision.Prediction' - 'CustomVision.Training' - 'Face' - 'FormRecognizer' - 'HealthInsights' - 'ImmersiveReader' - 'Internal.AllInOne' - 'LUIS' - 'LUIS.Authoring' - 'LanguageAuthoring' - 'MetricsAdvisor' - 'OpenAI' - 'Personalizer' - 'QnAMaker.v2' - 'SpeechServices' - 'TextAnalytics' - 'TextTranslation' -]) -param kind string - -@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') -@allowed([ - 'C2' - 'C3' - 'C4' - 'F0' - 'F1' - 'S' - 'S0' - 'S1' - 'S10' - 'S2' - 'S3' - 'S4' - 'S5' - 'S6' - 'S7' - 'S8' - 'S9' -]) -param sku string = 'S0' - -@description('Optional. Location for all Resources.') -param location string = resourceGroup().location - -import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The diagnostic settings of the service.') -param diagnosticSettings diagnosticSettingFullType[]? - -@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') -@allowed([ - 'Enabled' - 'Disabled' -]) -param publicNetworkAccess string? - -@description('Conditional. Subdomain name used for token-based authentication. Required if \'networkAcls\' or \'privateEndpoints\' are set.') -param customSubDomainName string? - -@description('Optional. A collection of rules governing the accessibility from specific network locations.') -param networkAcls object? - -import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') -param privateEndpoints privateEndpointSingleServiceType[]? - -import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The lock settings of the service.') -param lock lockType? - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[]? - -@description('Optional. Tags of the resource.') -param tags object? - -@description('Optional. List of allowed FQDN.') -param allowedFqdnList array? - -@description('Optional. The API properties for special APIs.') -param apiProperties object? - -@description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') -param disableLocalAuth bool = true - -import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The customer managed key definition.') -param customerManagedKey customerManagedKeyType? - -@description('Optional. The flag to enable dynamic throttling.') -param dynamicThrottlingEnabled bool = false - -@secure() -@description('Optional. Resource migration token.') -param migrationToken string? - -@description('Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists.') -param restore bool = false - -@description('Optional. Restrict outbound network access.') -param restrictOutboundNetworkAccess bool = true - -@description('Optional. The storage accounts for this resource.') -param userOwnedStorage array? - -import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The managed identity definition for this resource.') -param managedIdentities managedIdentityAllType? - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -@description('Optional. Array of deployments about cognitive service accounts to create.') -param deployments deploymentType[]? - -@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') -param secretsExportConfiguration secretsExportConfigurationType? - -@description('Optional. Enable/Disable project management feature for AI Foundry.') -param allowProjectManagement bool? - -var formattedUserAssignedIdentities = reduce( - map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), - {}, - (cur, next) => union(cur, next) -) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } - -var identity = !empty(managedIdentities) - ? { - type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') - : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) - userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null - } - : null - -#disable-next-line no-deployments-resources -resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { - name: '46d3xbcp.res.cognitiveservices-account.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } - } - } - } -} - -resource cMKKeyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { - name: last(split(customerManagedKey.?keyVaultResourceId!, '/')) - scope: resourceGroup( - split(customerManagedKey.?keyVaultResourceId!, '/')[2], - split(customerManagedKey.?keyVaultResourceId!, '/')[4] - ) - - resource cMKKey 'keys@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { - name: customerManagedKey.?keyName! - } -} - -resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { - name: last(split(customerManagedKey.?userAssignedIdentityResourceId!, '/')) - scope: resourceGroup( - split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[2], - split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[4] - ) -} - -var useExistingService = !empty(existingFoundryProjectResourceId) - -resource cognitiveServiceNew 'Microsoft.CognitiveServices/accounts@2025-12-01' = if(!useExistingService) { - name: name - kind: kind - identity: identity - location: location - tags: tags - sku: { - name: sku - } - properties: { - allowProjectManagement: allowProjectManagement // allows project management for Cognitive Services accounts in AI Foundry - FDP updates - customSubDomainName: customSubDomainName - networkAcls: !empty(networkAcls ?? {}) - ? { - defaultAction: networkAcls.?defaultAction - virtualNetworkRules: networkAcls.?virtualNetworkRules ?? [] - ipRules: networkAcls.?ipRules ?? [] - } - : null - publicNetworkAccess: publicNetworkAccess != null - ? publicNetworkAccess - : (!empty(networkAcls) ? 'Enabled' : 'Disabled') - allowedFqdnList: allowedFqdnList - apiProperties: apiProperties - disableLocalAuth: disableLocalAuth - encryption: !empty(customerManagedKey) - ? { - keySource: 'Microsoft.KeyVault' - keyVaultProperties: { - identityClientId: !empty(customerManagedKey.?userAssignedIdentityResourceId ?? '') - ? cMKUserAssignedIdentity.properties.clientId - : null - keyVaultUri: cMKKeyVault.properties.vaultUri - keyName: customerManagedKey!.keyName - keyVersion: !empty(customerManagedKey.?keyVersion ?? '') - ? customerManagedKey!.?keyVersion - : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) - } - } - : null - migrationToken: migrationToken - restore: restore - restrictOutboundNetworkAccess: restrictOutboundNetworkAccess - userOwnedStorage: userOwnedStorage - dynamicThrottlingEnabled: dynamicThrottlingEnabled - } -} - -var existingCognitiveServiceDetails = split(existingFoundryProjectResourceId, '/') - -resource cognitiveServiceExisting 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if(useExistingService) { - name: existingCognitiveServiceDetails[8] - scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) -} - -module cognitive_service_dependencies './modules/dependencies.bicep' = if(!useExistingService) { - params: { - projectName: projectName - projectDescription: projectDescription - name: cognitiveServiceNew.name - location: location - deployments: deployments - diagnosticSettings: diagnosticSettings - lock: lock - privateEndpoints: privateEndpoints - roleAssignments: roleAssignments - secretsExportConfiguration: secretsExportConfiguration - sku: sku - tags: tags - } -} - -module existing_cognitive_service_dependencies './modules/dependencies.bicep' = if(useExistingService) { - params: { - name: cognitiveServiceExisting.name - projectName: projectName - projectDescription: projectDescription - azureExistingAIProjectResourceId: existingFoundryProjectResourceId - location: location - deployments: deployments - diagnosticSettings: diagnosticSettings - lock: lock - privateEndpoints: privateEndpoints - roleAssignments: roleAssignments - secretsExportConfiguration: secretsExportConfiguration - sku: sku - tags: tags - } - scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) -} - -var cognitiveService = useExistingService ? cognitiveServiceExisting : cognitiveServiceNew - -@description('The name of the cognitive services account.') -output name string = useExistingService ? cognitiveServiceExisting.name : cognitiveServiceNew.name - -@description('The resource ID of the cognitive services account.') -output resourceId string = useExistingService ? cognitiveServiceExisting.id : cognitiveServiceNew.id - -@description('The resource group the cognitive services account was deployed into.') -output subscriptionId string = useExistingService ? existingCognitiveServiceDetails[2] : subscription().subscriptionId - -@description('The resource group the cognitive services account was deployed into.') -output resourceGroupName string = useExistingService ? existingCognitiveServiceDetails[4] : resourceGroup().name - -@description('The service endpoint of the cognitive services account.') -output endpoint string = useExistingService ? cognitiveServiceExisting.properties.endpoint : cognitiveService.properties.endpoint - -@description('All endpoints available for the cognitive services account, types depends on the cognitive service kind.') -output endpoints endpointType = useExistingService ? cognitiveServiceExisting.properties.endpoints : cognitiveService.properties.endpoints - -@description('The principal ID of the system assigned identity.') -output systemAssignedMIPrincipalId string? = useExistingService ? cognitiveServiceExisting.identity.principalId : cognitiveService.?identity.?principalId - -@description('The location the resource was deployed into.') -output location string = useExistingService ? cognitiveServiceExisting.location : cognitiveService.location - -import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') -output exportedSecrets secretsOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.exportedSecrets : cognitive_service_dependencies.outputs.exportedSecrets - -@description('The private endpoints of the congitive services account.') -output privateEndpoints privateEndpointOutputType[] = useExistingService ? existing_cognitive_service_dependencies.outputs.privateEndpoints : cognitive_service_dependencies.outputs.privateEndpoints - -import { aiProjectOutputType } from './modules/project.bicep' -output aiProjectInfo aiProjectOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.aiProjectInfo : cognitive_service_dependencies.outputs.aiProjectInfo - -// ================ // -// Definitions // -// ================ // - -@export() -@description('The type for the private endpoint output.') -type privateEndpointOutputType = { - @description('The name of the private endpoint.') - name: string - - @description('The resource ID of the private endpoint.') - resourceId: string - - @description('The group Id for the private endpoint Group.') - groupId: string? - - @description('The custom DNS configurations of the private endpoint.') - customDnsConfigs: { - @description('FQDN that resolves to private endpoint IP address.') - fqdn: string? - - @description('A list of private IP addresses of the private endpoint.') - ipAddresses: string[] - }[] - - @description('The IDs of the network interfaces associated with the private endpoint.') - networkInterfaceResourceIds: string[] -} - -@export() -@description('The type for a cognitive services account deployment.') -type deploymentType = { - @description('Optional. Specify the name of cognitive service account deployment.') - name: string? - - @description('Required. Properties of Cognitive Services account deployment model.') - model: { - @description('Required. The name of Cognitive Services account deployment model.') - name: string - - @description('Required. The format of Cognitive Services account deployment model.') - format: string - - @description('Required. The version of Cognitive Services account deployment model.') - version: string - } - - @description('Optional. The resource model definition representing SKU.') - sku: { - @description('Required. The name of the resource model definition representing SKU.') - name: string - - @description('Optional. The capacity of the resource model definition representing SKU.') - capacity: int? - - @description('Optional. The tier of the resource model definition representing SKU.') - tier: string? - - @description('Optional. The size of the resource model definition representing SKU.') - size: string? - - @description('Optional. The family of the resource model definition representing SKU.') - family: string? - }? - - @description('Optional. The name of RAI policy.') - raiPolicyName: string? - - @description('Optional. The version upgrade option.') - versionUpgradeOption: string? -} - -@export() -@description('The type for a cognitive services account endpoint.') -type endpointType = { - @description('Type of the endpoint.') - name: string? - @description('The endpoint URI.') - endpoint: string? -} - -@export() -@description('The type of the secrets exported to the provided Key Vault.') -type secretsExportConfigurationType = { - @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') - keyVaultResourceId: string - - @description('Optional. The name for the accessKey1 secret to create.') - accessKey1Name: string? - - @description('Optional. The name for the accessKey2 secret to create.') - accessKey2Name: string? -} diff --git a/infra/modules/account/modules/dependencies.bicep b/infra/modules/account/modules/dependencies.bicep deleted file mode 100644 index 55bb9ff7..00000000 --- a/infra/modules/account/modules/dependencies.bicep +++ /dev/null @@ -1,479 +0,0 @@ -@description('Required. The name of Cognitive Services account.') -param name string - -@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') -@allowed([ - 'C2' - 'C3' - 'C4' - 'F0' - 'F1' - 'S' - 'S0' - 'S1' - 'S10' - 'S2' - 'S3' - 'S4' - 'S5' - 'S6' - 'S7' - 'S8' - 'S9' -]) -param sku string = 'S0' - -@description('Optional. Location for all Resources.') -param location string = resourceGroup().location - -@description('Optional. Tags of the resource.') -param tags object? - -@description('Optional. Array of deployments about cognitive service accounts to create.') -param deployments deploymentType[]? - -@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') -param secretsExportConfiguration secretsExportConfigurationType? - -import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') -param privateEndpoints privateEndpointSingleServiceType[]? - -import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The lock settings of the service.') -param lock lockType? - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[]? - -import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The diagnostic settings of the service.') -param diagnosticSettings diagnosticSettingFullType[]? - -@description('Optional: Name for the project which needs to be created.') -param projectName string - -@description('Optional: Description for the project which needs to be created.') -param projectDescription string - -@description('Optional: Provide the existing project resource id in case if it needs to be reused') -param azureExistingAIProjectResourceId string = '' - -var builtInRoleNames = { - 'Cognitive Services Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68' - ) - 'Cognitive Services Custom Vision Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3' - ) - 'Cognitive Services Custom Vision Deployment': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '5c4089e1-6d96-4d2f-b296-c1bc7137275f' - ) - 'Cognitive Services Custom Vision Labeler': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '88424f51-ebe7-446f-bc41-7fa16989e96c' - ) - 'Cognitive Services Custom Vision Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '93586559-c37d-4a6b-ba08-b9f0940c2d73' - ) - 'Cognitive Services Custom Vision Trainer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b' - ) - 'Cognitive Services Data Reader (Preview)': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'b59867f0-fa02-499b-be73-45a86b5b3e1c' - ) - 'Cognitive Services Face Recognizer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '9894cab4-e18a-44aa-828b-cb588cd6f2d7' - ) - 'Cognitive Services Immersive Reader User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'b2de6794-95db-4659-8781-7e080d3f2b9d' - ) - 'Cognitive Services Language Owner': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f07febfe-79bc-46b1-8b37-790e26e6e498' - ) - 'Cognitive Services Language Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '7628b7b8-a8b2-4cdc-b46f-e9b35248918e' - ) - 'Cognitive Services Language Writer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8' - ) - 'Cognitive Services LUIS Owner': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f72c8140-2111-481c-87ff-72b910f6e3f8' - ) - 'Cognitive Services LUIS Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '18e81cdc-4e98-4e29-a639-e7d10c5a6226' - ) - 'Cognitive Services LUIS Writer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '6322a993-d5c9-4bed-b113-e49bbea25b27' - ) - 'Cognitive Services Metrics Advisor Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'cb43c632-a144-4ec5-977c-e80c4affc34a' - ) - 'Cognitive Services Metrics Advisor User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '3b20f47b-3825-43cb-8114-4bd2201156a8' - ) - 'Cognitive Services OpenAI Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'a001fd3d-188f-4b5d-821b-7da978bf7442' - ) - 'Cognitive Services OpenAI User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' - ) - 'Cognitive Services QnA Maker Editor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f4cc2bf9-21be-47a1-bdf1-5c5804381025' - ) - 'Cognitive Services QnA Maker Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '466ccd10-b268-4a11-b098-b4849f024126' - ) - 'Cognitive Services Speech Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '0e75ca1e-0464-4b4d-8b93-68208a576181' - ) - 'Cognitive Services Speech User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f2dc8367-1007-4938-bd23-fe263f013447' - ) - 'Cognitive Services User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'a97b65f3-24c7-4388-baec-2e87135dc908' - ) - 'Azure AI Developer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '64702f94-c441-49e6-a78b-ef80e0188fee' - ) - Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') - Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') - Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - 'Role Based Access Control Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' - ) - 'User Access Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' - ) -} - -var formattedRoleAssignments = [ - for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { - roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( - roleAssignment.roleDefinitionIdOrName, - '/providers/Microsoft.Authorization/roleDefinitions/' - ) - ? roleAssignment.roleDefinitionIdOrName - : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) - }) -] - -var enableReferencedModulesTelemetry = false - -resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { - name: name -} - -@batchSize(1) -resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = [ - for (deployment, index) in (deployments ?? []): { - parent: cognitiveService - name: deployment.?name ?? '${name}-deployments' - properties: { - model: deployment.model - raiPolicyName: deployment.?raiPolicyName - versionUpgradeOption: deployment.?versionUpgradeOption - } - sku: deployment.?sku ?? { - name: sku - capacity: sku.?capacity - tier: sku.?tier - size: sku.?size - family: sku.?family - } - } -] - -resource cognitiveService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: cognitiveService -} - -resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ - for (diagnosticSetting, index) in (diagnosticSettings ?? []): { - name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' - properties: { - storageAccountId: diagnosticSetting.?storageAccountResourceId - workspaceId: diagnosticSetting.?workspaceResourceId - eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId - eventHubName: diagnosticSetting.?eventHubName - metrics: [ - for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { - category: group.category - enabled: group.?enabled ?? true - timeGrain: null - } - ] - logs: [ - for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { - categoryGroup: group.?categoryGroup - category: group.?category - enabled: group.?enabled ?? true - } - ] - marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId - logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType - } - scope: cognitiveService - } -] - -module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.12.0' = [ - for (privateEndpoint, index) in (privateEndpoints ?? []): { - name: '${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}' - scope: resourceGroup( - split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], - split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] - ) - params: { - name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' - privateLinkServiceConnections: privateEndpoint.?isManualConnection != true - ? [ - { - name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' - properties: { - privateLinkServiceId: cognitiveService.id - groupIds: [ - privateEndpoint.?service ?? 'account' - ] - } - } - ] - : null - manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true - ? [ - { - name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' - properties: { - privateLinkServiceId: cognitiveService.id - groupIds: [ - privateEndpoint.?service ?? 'account' - ] - requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' - } - } - ] - : null - subnetResourceId: privateEndpoint.subnetResourceId - enableTelemetry: enableReferencedModulesTelemetry - location: privateEndpoint.?location ?? reference( - split(privateEndpoint.subnetResourceId, '/subnets/')[0], - '2020-06-01', - 'Full' - ).location - lock: privateEndpoint.?lock ?? lock - privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup - roleAssignments: privateEndpoint.?roleAssignments - tags: privateEndpoint.?tags ?? tags - customDnsConfigs: privateEndpoint.?customDnsConfigs - ipConfigurations: privateEndpoint.?ipConfigurations - applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds - customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName - } - } -] - -resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ - for (roleAssignment, index) in (formattedRoleAssignments ?? []): { - name: roleAssignment.?name ?? guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) - properties: { - roleDefinitionId: roleAssignment.roleDefinitionId - principalId: roleAssignment.principalId - description: roleAssignment.?description - principalType: roleAssignment.?principalType - condition: roleAssignment.?condition - conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set - delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId - } - scope: cognitiveService - } -] - -module secretsExport './keyVaultExport.bicep' = if (secretsExportConfiguration != null) { - name: '${uniqueString(deployment().name, location)}-secrets-kv' - scope: resourceGroup( - split(secretsExportConfiguration.?keyVaultResourceId!, '/')[2], - split(secretsExportConfiguration.?keyVaultResourceId!, '/')[4] - ) - params: { - keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId!, '/')) - secretsToSet: union( - [], - contains(secretsExportConfiguration!, 'accessKey1Name') - ? [ - { - name: secretsExportConfiguration!.?accessKey1Name - value: cognitiveService.listKeys().key1 - } - ] - : [], - contains(secretsExportConfiguration!, 'accessKey2Name') - ? [ - { - name: secretsExportConfiguration!.?accessKey2Name - value: cognitiveService.listKeys().key2 - } - ] - : [] - ) - } -} - -module aiProject 'project.bicep' = if(!empty(projectName) || !empty(azureExistingAIProjectResourceId)) { - name: take('${name}-ai-project-${projectName}-deployment', 64) - params: { - name: projectName - desc: projectDescription - aiServicesName: cognitiveService.name - location: location - tags: tags - azureExistingAIProjectResourceId: azureExistingAIProjectResourceId - } -} - -import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') -output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) - ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) - : {} - -@description('The private endpoints of the congitive services account.') -output privateEndpoints privateEndpointOutputType[] = [ - for (pe, index) in (privateEndpoints ?? []): { - name: cognitiveService_privateEndpoints[index].outputs.name - resourceId: cognitiveService_privateEndpoints[index].outputs.resourceId - groupId: cognitiveService_privateEndpoints[index].outputs.?groupId! - customDnsConfigs: cognitiveService_privateEndpoints[index].outputs.customDnsConfigs - networkInterfaceResourceIds: cognitiveService_privateEndpoints[index].outputs.networkInterfaceResourceIds - } -] - -import { aiProjectOutputType } from 'project.bicep' -output aiProjectInfo aiProjectOutputType = aiProject.outputs.aiProjectInfo - -// ================ // -// Definitions // -// ================ // - -@export() -@description('The type for the private endpoint output.') -type privateEndpointOutputType = { - @description('The name of the private endpoint.') - name: string - - @description('The resource ID of the private endpoint.') - resourceId: string - - @description('The group Id for the private endpoint Group.') - groupId: string? - - @description('The custom DNS configurations of the private endpoint.') - customDnsConfigs: { - @description('FQDN that resolves to private endpoint IP address.') - fqdn: string? - - @description('A list of private IP addresses of the private endpoint.') - ipAddresses: string[] - }[] - - @description('The IDs of the network interfaces associated with the private endpoint.') - networkInterfaceResourceIds: string[] -} - -@export() -@description('The type for a cognitive services account deployment.') -type deploymentType = { - @description('Optional. Specify the name of cognitive service account deployment.') - name: string? - - @description('Required. Properties of Cognitive Services account deployment model.') - model: { - @description('Required. The name of Cognitive Services account deployment model.') - name: string - - @description('Required. The format of Cognitive Services account deployment model.') - format: string - - @description('Required. The version of Cognitive Services account deployment model.') - version: string - } - - @description('Optional. The resource model definition representing SKU.') - sku: { - @description('Required. The name of the resource model definition representing SKU.') - name: string - - @description('Optional. The capacity of the resource model definition representing SKU.') - capacity: int? - - @description('Optional. The tier of the resource model definition representing SKU.') - tier: string? - - @description('Optional. The size of the resource model definition representing SKU.') - size: string? - - @description('Optional. The family of the resource model definition representing SKU.') - family: string? - }? - - @description('Optional. The name of RAI policy.') - raiPolicyName: string? - - @description('Optional. The version upgrade option.') - versionUpgradeOption: string? -} - -@export() -@description('The type for a cognitive services account endpoint.') -type endpointType = { - @description('Type of the endpoint.') - name: string? - @description('The endpoint URI.') - endpoint: string? -} - -@export() -@description('The type of the secrets exported to the provided Key Vault.') -type secretsExportConfigurationType = { - @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') - keyVaultResourceId: string - - @description('Optional. The name for the accessKey1 secret to create.') - accessKey1Name: string? - - @description('Optional. The name for the accessKey2 secret to create.') - accessKey2Name: string? -} diff --git a/infra/modules/account/modules/keyVaultExport.bicep b/infra/modules/account/modules/keyVaultExport.bicep deleted file mode 100644 index ccbcf14b..00000000 --- a/infra/modules/account/modules/keyVaultExport.bicep +++ /dev/null @@ -1,43 +0,0 @@ -// ============== // -// Parameters // -// ============== // - -@description('Required. The name of the Key Vault to set the secrets in.') -param keyVaultName string - -import { secretToSetType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Required. The secrets to set in the Key Vault.') -param secretsToSet secretToSetType[] - -// ============= // -// Resources // -// ============= // - -resource keyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = { - name: keyVaultName -} - -resource secrets 'Microsoft.KeyVault/vaults/secrets@2026-02-01' = [ - for secret in secretsToSet: { - name: secret.name - parent: keyVault - properties: { - value: secret.value - } - } -] - -// =========== // -// Outputs // -// =========== // - -import { secretSetOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('The references to the secrets exported to the provided Key Vault.') -output secretsSet secretSetOutputType[] = [ - #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value - for index in range(0, length(secretsToSet ?? [])): { - secretResourceId: secrets[index].id - secretUri: secrets[index].properties.secretUri - secretUriWithVersion: secrets[index].properties.secretUriWithVersion - } -] diff --git a/infra/modules/account/modules/project.bicep b/infra/modules/account/modules/project.bicep deleted file mode 100644 index 3a1620d2..00000000 --- a/infra/modules/account/modules/project.bicep +++ /dev/null @@ -1,62 +0,0 @@ -@description('Required. Name of the AI Services project.') -param name string - -@description('Required. The location of the Project resource.') -param location string = resourceGroup().location - -@description('Optional. The description of the AI Foundry project to create. Defaults to the project name.') -param desc string = name - -@description('Required. Name of the existing Cognitive Services resource to create the AI Foundry project in.') -param aiServicesName string - -@description('Optional. Tags to be applied to the resources.') -param tags object = {} - -@description('Optional. Use this parameter to use an existing AI project resource ID from different resource group') -param azureExistingAIProjectResourceId string = '' - -// // Extract components from existing AI Project Resource ID if provided -var useExistingProject = !empty(azureExistingAIProjectResourceId) -var existingProjName = useExistingProject ? last(split(azureExistingAIProjectResourceId, '/')) : '' -var existingProjEndpoint = useExistingProject ? format('https://{0}.services.ai.azure.com/api/projects/{1}', aiServicesName, existingProjName) : '' - -// Reference to cognitive service in current resource group for new projects -resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { - name: aiServicesName -} - -// Create new AI project only if not reusing existing one -resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = if(!useExistingProject) { - parent: cogServiceReference - name: name - tags: tags - location: location - identity: { - type: 'SystemAssigned' - } - properties: { - description: desc - displayName: name - } -} - -@description('AI Project metadata including name, resource ID, and API endpoint.') -output aiProjectInfo aiProjectOutputType = { - name: useExistingProject ? existingProjName : aiProject.name - resourceId: useExistingProject ? azureExistingAIProjectResourceId : aiProject.id - apiEndpoint: useExistingProject ? existingProjEndpoint : aiProject.properties.endpoints['AI Foundry API'] -} - -@export() -@description('Output type representing AI project information.') -type aiProjectOutputType = { - @description('Required. Name of the AI project.') - name: string - - @description('Required. Resource ID of the AI project.') - resourceId: string - - @description('Required. API endpoint for the AI project.') - apiEndpoint: string -} diff --git a/infra/modules/container-registry.bicep b/infra/modules/container-registry.bicep deleted file mode 100644 index 52ee5c2b..00000000 --- a/infra/modules/container-registry.bicep +++ /dev/null @@ -1,92 +0,0 @@ -metadata name = 'Container Registry Module' -// AVM-compliant Azure Container Registry deployment - -@description('Required. The name of the Azure Container Registry.') -param acrName string - -@description('Required. The location of the Azure Container Registry.') -param location string - -@description('Optional. SKU for the Azure Container Registry.') -param acrSku string = 'Basic' - -@description('Optional. Public network access setting for the Azure Container Registry.') -param publicNetworkAccess string = 'Enabled' - -@description('Optional. Zone redundancy setting for the Azure Container Registry.') -param zoneRedundancy string = 'Disabled' - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[]? - -@description('Optional. Tags to be applied to the Container Registry.') -param tags object = {} - -@description('Required. Enable telemetry for the AVM deployment.') -param enableTelemetry bool - -@description('Required. Enable Redundancy for the AVM deployment.') -param enableRedundancy bool - -@description('Required. The replica location for the Azure Container Registry replication, if redundancy is enabled.') -param replicaLocation string - -@description('Optional. Enable private networking for the Container Registry.') -param enablePrivateNetworking bool = false - -@description('Optional. Backend subnet resource ID for private endpoints.') -param backendSubnetResourceId string = '' - -@description('Optional. Private DNS zone resource ID for Container Registry.') -param privateDnsZoneResourceId string = '' - -module avmContainerRegistry 'br/public:avm/res/container-registry/registry:0.12.1' = { - name: acrName - params: { - name: acrName - location: location - acrSku: acrSku - publicNetworkAccess: publicNetworkAccess - zoneRedundancy: zoneRedundancy - roleAssignments: roleAssignments - tags: tags - enableTelemetry: enableTelemetry - replications: enableRedundancy - ? [ - { - location: replicaLocation - name: 'acrrepl${replace(replicaLocation, '-', '')}' - } - ] - : null - // WAF aligned configuration for Private Networking - Network access restrictions - // Network rule set features require Premium SKU; default action is always set ('Deny' for private networking, otherwise 'Allow'), while additional restrictions are only set when private networking is enabled - networkRuleSetDefaultAction: enablePrivateNetworking ? 'Deny' : 'Allow' - networkRuleSetIpRules: enablePrivateNetworking ? [] : null - exportPolicyStatus: enablePrivateNetworking ? 'disabled' : null - privateEndpoints: enablePrivateNetworking - ? [ - { - name: 'pep-acr-${acrName}' - customNetworkInterfaceName: 'nic-acr-${acrName}' - privateDnsZoneGroup: !empty(privateDnsZoneResourceId) - ? { - privateDnsZoneGroupConfigs: [ - { - name: 'acr-dns-zone-group' - privateDnsZoneResourceId: privateDnsZoneResourceId - } - ] - } - : null - subnetResourceId: backendSubnetResourceId - } - ] - : [] - } -} - -output name string = avmContainerRegistry.outputs.name -output resourceId string = avmContainerRegistry.outputs.resourceId -output loginServer string = avmContainerRegistry.outputs.loginServer diff --git a/infra/modules/log-analytics-workspace.bicep b/infra/modules/log-analytics-workspace.bicep deleted file mode 100644 index 6b1c51e9..00000000 --- a/infra/modules/log-analytics-workspace.bicep +++ /dev/null @@ -1,105 +0,0 @@ -@description('The name of Log analytics Workspace') -param name string - -@description('Location for the Resource.') -param location string = resourceGroup().location - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -@description('Optional. Tags to be applied to the resources.') -param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} - -@description('Optional: Existing Log Analytics Workspace Resource ID') -param existingLogAnalyticsWorkspaceId string = '' - -@description('Optional. Enable Private Networking for Log Analytics Workspace.') -param enablePrivateNetworking bool = false - -@description('Optional. Enable Redundancy for Log Analytics Workspace.') -param enableRedundancy bool = false - -@description('Optional. The replica location for Log Analytics Workspace, if redundancy is enabled.') -param replicaLocation string = '' - -var useExistingWorkspace = !empty(existingLogAnalyticsWorkspaceId) - -var existingLawSubscription = useExistingWorkspace ? split(existingLogAnalyticsWorkspaceId, '/')[2] : '' -var existingLawResourceGroup = useExistingWorkspace ? split(existingLogAnalyticsWorkspaceId, '/')[4] : '' -var existingLawName = useExistingWorkspace ? split(existingLogAnalyticsWorkspaceId, '/')[8] : '' - -module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.15.0' = if (!useExistingWorkspace) { - name: take('avm.res.operational-insights.workspace.${name}', 64) - params: { - name: name - tags: tags - location: location - enableTelemetry: enableTelemetry - skuName: 'PerGB2018' - dataRetention: 365 - features: { enableLogAccessUsingOnlyResourcePermissions: true } - diagnosticSettings: [{ useThisWorkspace: true }] - // WAF aligned configuration for Redundancy - dailyQuotaGb: enableRedundancy ? '150' : null //WAF recommendation: 150 GB per day is a good starting point for most workloads - replication: enableRedundancy - ? { - enabled: true - location: replicaLocation - } - : null - // WAF aligned configuration for Private Networking - publicNetworkAccessForIngestion: enablePrivateNetworking ? 'Disabled' : 'Enabled' - publicNetworkAccessForQuery: enablePrivateNetworking ? 'Disabled' : 'Enabled' - dataSources: enablePrivateNetworking - ? [ - { - tags: tags - eventLogName: 'Application' - eventTypes: [ - { - eventType: 'Error' - } - { - eventType: 'Warning' - } - { - eventType: 'Information' - } - ] - kind: 'WindowsEvent' - name: 'applicationEvent' - } - { - counterName: '% Processor Time' - instanceName: '*' - intervalSeconds: 60 - kind: 'WindowsPerformanceCounter' - name: 'windowsPerfCounter1' - objectName: 'Processor' - } - { - kind: 'IISLogs' - name: 'sampleIISLog1' - state: 'OnPremiseEnabled' - } - ] - : null - } -} - -resource existingLogAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2025-07-01' existing = if (useExistingWorkspace) { - name: existingLawName - scope: resourceGroup(existingLawSubscription, existingLawResourceGroup) -} - -var lawKeys = useExistingWorkspace ? listKeys(existingLogAnalyticsWorkspace.id, '2020-08-01') : logAnalyticsWorkspace.outputs.primarySharedKey - -output resourceId string = useExistingWorkspace ? existingLogAnalyticsWorkspace.id : logAnalyticsWorkspace.outputs.resourceId -output logAnalyticsWorkspaceId string = useExistingWorkspace ? existingLogAnalyticsWorkspace.properties.customerId : logAnalyticsWorkspace.outputs.logAnalyticsWorkspaceId -@secure() -output primarySharedKey string = useExistingWorkspace ? lawKeys.primarySharedKey : logAnalyticsWorkspace.outputs.primarySharedKey -output location string = useExistingWorkspace ? existingLogAnalyticsWorkspace!.location : logAnalyticsWorkspace!.outputs.location -output name string = useExistingWorkspace ? existingLogAnalyticsWorkspace!.name : logAnalyticsWorkspace!.outputs.name diff --git a/infra/modules/managed-identity.bicep b/infra/modules/managed-identity.bicep deleted file mode 100644 index aa6e4915..00000000 --- a/infra/modules/managed-identity.bicep +++ /dev/null @@ -1,25 +0,0 @@ -// ========== Managed Identity ========== // -@description('Required. The name of the managed identity.') -param name string - -@description('Required. The location of the managed identity.') -param location string - -@description('Required. Tags to be applied to the managed identity.') -param tags object - -@description('Required. Enable telemetry for the AVM deployment.') -param enableTelemetry bool - -module avmManagedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { - name: name - params: { - name: name - location: location - tags: tags - enableTelemetry: enableTelemetry - } -} - -output resourceId string = avmManagedIdentity.outputs.resourceId -output principalId string = avmManagedIdentity.outputs.principalId diff --git a/infra/modules/virtualNetwork.bicep b/infra/modules/virtualNetwork.bicep deleted file mode 100644 index a15a385a..00000000 --- a/infra/modules/virtualNetwork.bicep +++ /dev/null @@ -1,397 +0,0 @@ -/****************************************************************************************************************************/ -// Networking - NSGs, VNET and Subnets. Each subnet has its own NSG -/****************************************************************************************************************************/ -@description('Required. Name of the virtual network.') -param name string - -@description('Optional. Azure region to deploy resources.') -param location string = resourceGroup().location - -@description('Required. An Array of 1 or more IP Address Prefixes for the Virtual Network.') -param addressPrefixes array - -@description('Optional. An array of subnets to be created within the virtual network. Each subnet can have its own configuration and associated Network Security Group (NSG).') -param subnets subnetType[] = [ - { - name: 'containers' - addressPrefixes: ['10.0.2.0/24'] // /24 (10.0.2.0 - 10.0.2.255), 256 addresses - delegation: 'Microsoft.App/environments' - networkSecurityGroup: { - name: 'nsg-containers' - securityRules: [ - //Inbound Rules - { - name: 'AllowHttpsInbound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 100 - protocol: 'Tcp' - sourceAddressPrefix: 'Internet' - sourcePortRange: '*' - destinationPortRanges: ['443', '80'] - destinationAddressPrefixes: ['10.0.2.0/24'] - } - } - { - name: 'AllowAzureLoadBalancerInbound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 102 - protocol: '*' - sourceAddressPrefix: 'AzureLoadBalancer' - sourcePortRange: '*' - destinationPortRanges: ['30000-32767'] - destinationAddressPrefixes: ['10.0.2.0/24'] - } - } - { - name: 'AllowSideCarsInbound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 103 - protocol: '*' - sourcePortRange: '*' - sourceAddressPrefixes: ['10.0.2.0/24'] - destinationPortRange: '*' - destinationAddressPrefix: '*' - } - } - //Outbound Rules - { - name: 'AllowOutboundToAzureServices' - properties: { - access: 'Allow' - direction: 'Outbound' - priority: 200 - protocol: '*' - sourceAddressPrefixes: ['10.0.2.0/24'] - sourcePortRange: '*' - destinationPortRange: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'deny-hop-outbound' - properties: { - access: 'Deny' - direction: 'Outbound' - priority: 100 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['3389', '22'] - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: '*' - } - } - ] - } - } - { - name: 'backend' - addressPrefixes: ['10.0.0.0/24'] // /24 (10.0.0.0 - 10.0.0.255), 256 addresses - privateEndpointNetworkPolicies: 'Disabled' - privateLinkServiceNetworkPolicies: 'Disabled' - networkSecurityGroup: { - name: 'nsg-backend' - securityRules: [ - { - name: 'Deny-hop-outbound' - properties: { - access: 'Deny' - direction: 'Outbound' - priority: 200 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['3389', '22'] - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: '*' - } - } - ] - } - } - { - name: 'AzureBastionSubnet' // Required name for Azure Bastion - addressPrefixes: ['10.0.1.32/27'] - networkSecurityGroup: { - name: 'nsg-bastion' - securityRules: [ - { - name: 'AllowGatewayManager' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 2702 - protocol: '*' - sourcePortRange: '*' - destinationPortRange: '443' - sourceAddressPrefix: 'GatewayManager' - destinationAddressPrefix: '*' - } - } - { - name: 'AllowHttpsInBound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 2703 - protocol: '*' - sourcePortRange: '*' - destinationPortRange: '443' - sourceAddressPrefix: 'Internet' - destinationAddressPrefix: '*' - } - } - { - name: 'AllowSshRdpOutbound' - properties: { - access: 'Allow' - direction: 'Outbound' - priority: 100 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['22', '3389'] - sourceAddressPrefix: '*' - destinationAddressPrefix: 'VirtualNetwork' - } - } - { - name: 'AllowAzureCloudOutbound' - properties: { - access: 'Allow' - direction: 'Outbound' - priority: 110 - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '443' - sourceAddressPrefix: '*' - destinationAddressPrefix: 'AzureCloud' - } - } - ] - } - } - { - name: 'admin' - addressPrefixes: ['10.0.1.0/27'] - networkSecurityGroup: { - name: 'nsg-admin' - securityRules: [ - { - name: 'Deny-hop-outbound' - properties: { - access: 'Deny' - direction: 'Outbound' - priority: 200 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['3389', '22'] - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: '*' - } - } - ] - } - } -] - -@description('Optional. Tags to be applied to the resources.') -param tags object = {} - -@description('Required. The resource ID of the Log Analytics Workspace to send diagnostic logs to.') -param logAnalyticsWorkspaceId string - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -@description('Required. Suffix for resource naming.') -param resourceSuffix string - -// VM Size Notes: -// 1 B-series VMs (like Standard_B2ms) do not support accelerated networking. -// 2 Pick a VM size that supports accelerated networking + Premium SSD (the usual jump-box candidates): -// Standard_D2s_v5 (2 vCPU, 8 GiB RAM, Premium SSD/v2/Ultra) // DEFAULT - current-gen Intel, broad regional availability. -// Standard_D2as_v5 (2 vCPU, 8 GiB RAM, Premium SSD/Ultra) // AMD alternative, typically ~15% cheaper. -// Standard_D2s_v4 (2 vCPU, 8 GiB RAM, Premium SSD) // Previous gen, also broadly available. -// Standard_DS2_v2 (2 vCPU, 7 GiB RAM, Premium SSD) // Legacy SKU, being retired from some regions - avoid for new deployments. -// 3 A-series (Av2) is NOT suitable: no Premium SSD support, no accelerated networking. - -// Subnet Classless Inter-Doman Routing (CIDR) Sizing Reference Table (Best Practices) -// | CIDR | # of Addresses | # of /24s | Notes | -// |-----------|---------------|-----------|----------------------------------------| -// | /24 | 256 | 1 | Smallest recommended for Azure subnets | -// | /23 | 512 | 2 | Good for 1-2 workloads per subnet | -// | /22 | 1024 | 4 | Good for 2-4 workloads per subnet | -// | /21 | 2048 | 8 | | -// | /20 | 4096 | 16 | Used for default VNet in this solution | -// | /19 | 8192 | 32 | | -// | /18 | 16384 | 64 | | -// | /17 | 32768 | 128 | | -// | /16 | 65536 | 256 | | -// | /15 | 131072 | 512 | | -// | /14 | 262144 | 1024 | | -// | /13 | 524288 | 2048 | | -// | /12 | 1048576 | 4096 | | -// | /11 | 2097152 | 8192 | | -// | /10 | 4194304 | 16384 | | -// | /9 | 8388608 | 32768 | | -// | /8 | 16777216 | 65536 | | -// -// Best Practice Notes: -// - Use /24 as the minimum subnet size for Azure (smaller subnets are not supported for most services). -// - Plan for future growth: allocate larger address spaces (e.g., /20 or /21 for VNets) to allow for new subnets. -// - Avoid overlapping address spaces with on-premises or other VNets. -// - Use contiguous, non-overlapping ranges for subnets. -// - Document subnet usage and purpose in code comments. -// - For AVM modules, ensure only one delegation per subnet and leave delegations empty if not required. - -// 1. Create NSGs for subnets -// using AVM Network Security Group module -// https://github.com/Azure/bicep-registry-modules/tree/main/avm/res/network/network-security-group - -@batchSize(1) -module nsgs 'br/public:avm/res/network/network-security-group:0.5.3' = [ - for (subnet, i) in subnets: if (!empty(subnet.?networkSecurityGroup)) { - name: take('avm.res.network.network-security-group.${subnet.?networkSecurityGroup.name}.${resourceSuffix}', 64) - params: { - name: '${subnet.?networkSecurityGroup.name}-${resourceSuffix}' - location: location - securityRules: subnet.?networkSecurityGroup.securityRules - tags: tags - enableTelemetry: enableTelemetry - } - } -] - -// 2. Create VNet and subnets, with subnets associated with corresponding NSGs -// using AVM Virtual Network module -// https://github.com/Azure/bicep-registry-modules/tree/main/avm/res/network/virtual-network - -module virtualNetwork 'br/public:avm/res/network/virtual-network:0.8.1' = { - name: take('avm.res.network.virtual-network.${name}', 64) - params: { - name: name - location: location - addressPrefixes: addressPrefixes - subnets: [ - for (subnet, i) in subnets: { - name: subnet.name - addressPrefixes: subnet.?addressPrefixes - networkSecurityGroupResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null - privateEndpointNetworkPolicies: subnet.?privateEndpointNetworkPolicies - privateLinkServiceNetworkPolicies: subnet.?privateLinkServiceNetworkPolicies - delegation: subnet.?delegation - } - ] - diagnosticSettings: [ - { - name: 'vnetDiagnostics' - workspaceResourceId: logAnalyticsWorkspaceId - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] - metricCategories: [ - { - category: 'AllMetrics' - enabled: true - } - ] - } - ] - tags: tags - enableTelemetry: enableTelemetry - } -} - -output name string = virtualNetwork.outputs.name -output resourceId string = virtualNetwork.outputs.resourceId - -// combined output array that holds subnet details along with NSG information -output subnets subnetOutputType[] = [ - for (subnet, i) in subnets: { - name: subnet.name - resourceId: virtualNetwork.outputs.subnetResourceIds[i] - nsgName: !empty(subnet.?networkSecurityGroup) ? subnet.?networkSecurityGroup.name : null - nsgResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null - } -] - -// Dynamic outputs for individual subnets for backward compatibility -output containersSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'containers') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'containers')] - : '' -output backendSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'backend') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'backend')] - : '' -output bastionSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'AzureBastionSubnet') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'AzureBastionSubnet')] - : '' -output adminSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'admin') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'admin')] - : '' - -@export() -@description('Custom type definition for subnet resource information as output') -type subnetOutputType = { - @description('The name of the subnet.') - name: string - - @description('The resource ID of the subnet.') - resourceId: string - - @description('The name of the associated network security group, if any.') - nsgName: string? - - @description('The resource ID of the associated network security group, if any.') - nsgResourceId: string? -} - -@export() -@description('Custom type definition for subnet configuration') -type subnetType = { - @description('Required. The Name of the subnet resource.') - name: string - - @description('Required. Prefixes for the subnet.') // Required to ensure at least one prefix is provided - addressPrefixes: string[] - - @description('Optional. The delegation to enable on the subnet.') - delegation: string? - - @description('Optional. enable or disable apply network policies on private endpoint in the subnet.') - privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? - - @description('Optional. Enable or disable apply network policies on private link service in the subnet.') - privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? - - @description('Optional. Network Security Group configuration for the subnet.') - networkSecurityGroup: networkSecurityGroupType? - - @description('Optional. The resource ID of the route table to assign to the subnet.') - routeTableResourceId: string? - - @description('Optional. An array of service endpoint policies.') - serviceEndpointPolicies: object[]? - - @description('Optional. The service endpoints to enable on the subnet.') - serviceEndpoints: string[]? - - @description('Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet.') - defaultOutboundAccess: bool? -} - -@export() -@description('Custom type definition for network security group configuration') -type networkSecurityGroupType = { - @description('Required. The name of the network security group.') - name: string - - @description('Required. The security rules for the network security group.') - securityRules: object[] -} diff --git a/infra/scripts/post-provision/.gitkeep b/infra/scripts/post-provision/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/infra/scripts/pre-provision/.gitkeep b/infra/scripts/pre-provision/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/infra/scripts/utilities/.gitkeep b/infra/scripts/utilities/.gitkeep new file mode 100644 index 00000000..e69de29b From bab364b443b90ab47fb08cf85b8a2d71df9c7880 Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Wed, 10 Jun 2026 16:34:35 +0530 Subject: [PATCH 3/8] feat(infra): restructure modules to GSA-compatible data structure Align infra/avm/modules and infra/bicep/modules folder structure with the unified GSA module pattern from agentic-applications repo. Added module categories: - security/ (key-vault) - fabric/ (fabric-capacity) Added modules within existing categories: - ai/: ai-foundry-connection, ai-foundry-model-deployment, ai-foundry-project, ai-services, existing-project-setup - compute/: app-service-plan, app-service, container-app-environment, container-app, container-instance, function-app, kubernetes, maintenance-configuration, proximity-placement-group, virtual-machine - data/: app-configuration, cosmos-db-nosql, event-grid, event-hub, postgresql-flexible-server, sql-database, storage-account - identity/: cross-scope-role-assignment, role-assignments - monitoring/: app-insights, data-collection-rule, portal-dashboard - networking/: bastion-host, private-dns-zone, private-endpoint Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../modules/ai/ai-foundry-connection.bicep | 84 +++ .../ai/ai-foundry-model-deployment.bicep | 64 +++ infra/avm/modules/ai/ai-foundry-project.bicep | 135 +++++ infra/avm/modules/ai/ai-foundry.bicep | 421 +++++++++++++++ infra/avm/modules/ai/ai-search.bicep | 121 +++++ infra/avm/modules/ai/ai-services.bicep | 121 +++++ .../modules/ai/existing-project-setup.bicep | 50 ++ .../avm/modules/ai/modules/dependencies.bicep | 479 ++++++++++++++++++ .../modules/ai/modules/keyVaultExport.bicep | 43 ++ infra/avm/modules/ai/modules/project.bicep | 62 +++ .../modules/compute/app-service-plan.bicep | 67 +++ infra/avm/modules/compute/app-service.bicep | 115 +++++ .../compute/container-app-environment.bicep | 95 ++++ infra/avm/modules/compute/container-app.bicep | 105 ++++ .../modules/compute/container-instance.bicep | 120 +++++ .../modules/compute/container-registry.bicep | 104 ++++ infra/avm/modules/compute/function-app.bicep | 95 ++++ infra/avm/modules/compute/kubernetes.bicep | 158 ++++++ .../compute/maintenance-configuration.bicep | 84 +++ .../compute/proximity-placement-group.bicep | 51 ++ .../avm/modules/compute/virtual-machine.bicep | 157 ++++++ .../avm/modules/data/app-configuration.bicep | 98 ++++ infra/avm/modules/data/cosmos-db-mongo.bicep | 137 +++++ infra/avm/modules/data/cosmos-db-nosql.bicep | 146 ++++++ infra/avm/modules/data/event-grid.bicep | 65 +++ infra/avm/modules/data/event-hub.bicep | 92 ++++ .../data/postgresql-flexible-server.bicep | 148 ++++++ infra/avm/modules/data/sql-database.bicep | 140 +++++ infra/avm/modules/data/storage-account.bicep | 135 +++++ .../avm/modules/fabric/fabric-capacity.bicep | 72 +++ .../cross-scope-role-assignment.bicep | 37 ++ .../modules/identity/managed-identity.bicep | 49 ++ .../modules/identity/role-assignments.bicep | 280 ++++++++++ .../avm/modules/monitoring/app-insights.bicep | 76 +++ .../monitoring/data-collection-rule.bicep | 149 ++++++ .../modules/monitoring/log-analytics.bicep | 90 ++++ .../modules/monitoring/portal-dashboard.bicep | 53 ++ .../avm/modules/networking/bastion-host.bicep | 85 ++++ .../modules/networking/private-dns-zone.bicep | 40 ++ .../modules/networking/private-endpoint.bicep | 52 ++ .../modules/networking/virtual-network.bicep | 303 +++++++++++ infra/avm/modules/security/key-vault.bicep | 109 ++++ .../modules/ai/ai-foundry-connection.bicep | 84 +++ .../ai/ai-foundry-model-deployment.bicep | 66 +++ .../bicep/modules/ai/ai-foundry-project.bicep | 111 ++++ infra/bicep/modules/ai/ai-foundry.bicep | 74 +++ .../bicep/modules/ai/ai-search-identity.bicep | 65 +++ infra/bicep/modules/ai/ai-search.bicep | 97 ++++ infra/bicep/modules/ai/ai-services.bicep | 87 ++++ .../modules/ai/existing-project-setup.bicep | 51 ++ .../modules/compute/app-service-plan.bicep | 60 +++ infra/bicep/modules/compute/app-service.bicep | 111 ++++ .../compute/container-app-environment.bicep | 63 +++ .../bicep/modules/compute/container-app.bicep | 117 +++++ .../modules/compute/container-instance.bicep | 119 +++++ .../modules/compute/container-registry.bicep | 75 +++ .../bicep/modules/compute/function-app.bicep | 100 ++++ infra/bicep/modules/compute/kubernetes.bicep | 134 +++++ .../modules/data/app-configuration.bicep | 63 +++ .../bicep/modules/data/cosmos-db-mongo.bicep | 114 +++++ .../bicep/modules/data/cosmos-db-nosql.bicep | 90 ++++ infra/bicep/modules/data/event-grid.bicep | 81 +++ infra/bicep/modules/data/event-hub.bicep | 62 +++ .../data/postgresql-flexible-server.bicep | 133 +++++ infra/bicep/modules/data/sql-database.bicep | 115 +++++ .../bicep/modules/data/storage-account.bicep | 101 ++++ .../modules/fabric/fabric-capacity.bicep | 72 +++ .../cross-scope-role-assignment.bicep | 37 ++ .../modules/identity/managed-identity.bicep | 43 ++ .../modules/identity/role-assignments.bicep | 350 +++++++++++++ .../modules/monitoring/app-insights.bicep | 72 +++ .../modules/monitoring/log-analytics.bicep | 58 +++ .../modules/monitoring/portal-dashboard.bicep | 49 ++ infra/bicep/modules/security/key-vault.bicep | 81 +++ 74 files changed, 8022 insertions(+) create mode 100644 infra/avm/modules/ai/ai-foundry-connection.bicep create mode 100644 infra/avm/modules/ai/ai-foundry-model-deployment.bicep create mode 100644 infra/avm/modules/ai/ai-foundry-project.bicep create mode 100644 infra/avm/modules/ai/ai-foundry.bicep create mode 100644 infra/avm/modules/ai/ai-search.bicep create mode 100644 infra/avm/modules/ai/ai-services.bicep create mode 100644 infra/avm/modules/ai/existing-project-setup.bicep create mode 100644 infra/avm/modules/ai/modules/dependencies.bicep create mode 100644 infra/avm/modules/ai/modules/keyVaultExport.bicep create mode 100644 infra/avm/modules/ai/modules/project.bicep create mode 100644 infra/avm/modules/compute/app-service-plan.bicep create mode 100644 infra/avm/modules/compute/app-service.bicep create mode 100644 infra/avm/modules/compute/container-app-environment.bicep create mode 100644 infra/avm/modules/compute/container-app.bicep create mode 100644 infra/avm/modules/compute/container-instance.bicep create mode 100644 infra/avm/modules/compute/container-registry.bicep create mode 100644 infra/avm/modules/compute/function-app.bicep create mode 100644 infra/avm/modules/compute/kubernetes.bicep create mode 100644 infra/avm/modules/compute/maintenance-configuration.bicep create mode 100644 infra/avm/modules/compute/proximity-placement-group.bicep create mode 100644 infra/avm/modules/compute/virtual-machine.bicep create mode 100644 infra/avm/modules/data/app-configuration.bicep create mode 100644 infra/avm/modules/data/cosmos-db-mongo.bicep create mode 100644 infra/avm/modules/data/cosmos-db-nosql.bicep create mode 100644 infra/avm/modules/data/event-grid.bicep create mode 100644 infra/avm/modules/data/event-hub.bicep create mode 100644 infra/avm/modules/data/postgresql-flexible-server.bicep create mode 100644 infra/avm/modules/data/sql-database.bicep create mode 100644 infra/avm/modules/data/storage-account.bicep create mode 100644 infra/avm/modules/fabric/fabric-capacity.bicep create mode 100644 infra/avm/modules/identity/cross-scope-role-assignment.bicep create mode 100644 infra/avm/modules/identity/managed-identity.bicep create mode 100644 infra/avm/modules/identity/role-assignments.bicep create mode 100644 infra/avm/modules/monitoring/app-insights.bicep create mode 100644 infra/avm/modules/monitoring/data-collection-rule.bicep create mode 100644 infra/avm/modules/monitoring/log-analytics.bicep create mode 100644 infra/avm/modules/monitoring/portal-dashboard.bicep create mode 100644 infra/avm/modules/networking/bastion-host.bicep create mode 100644 infra/avm/modules/networking/private-dns-zone.bicep create mode 100644 infra/avm/modules/networking/private-endpoint.bicep create mode 100644 infra/avm/modules/networking/virtual-network.bicep create mode 100644 infra/avm/modules/security/key-vault.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry-connection.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry-model-deployment.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry-project.bicep create mode 100644 infra/bicep/modules/ai/ai-foundry.bicep create mode 100644 infra/bicep/modules/ai/ai-search-identity.bicep create mode 100644 infra/bicep/modules/ai/ai-search.bicep create mode 100644 infra/bicep/modules/ai/ai-services.bicep create mode 100644 infra/bicep/modules/ai/existing-project-setup.bicep create mode 100644 infra/bicep/modules/compute/app-service-plan.bicep create mode 100644 infra/bicep/modules/compute/app-service.bicep create mode 100644 infra/bicep/modules/compute/container-app-environment.bicep create mode 100644 infra/bicep/modules/compute/container-app.bicep create mode 100644 infra/bicep/modules/compute/container-instance.bicep create mode 100644 infra/bicep/modules/compute/container-registry.bicep create mode 100644 infra/bicep/modules/compute/function-app.bicep create mode 100644 infra/bicep/modules/compute/kubernetes.bicep create mode 100644 infra/bicep/modules/data/app-configuration.bicep create mode 100644 infra/bicep/modules/data/cosmos-db-mongo.bicep create mode 100644 infra/bicep/modules/data/cosmos-db-nosql.bicep create mode 100644 infra/bicep/modules/data/event-grid.bicep create mode 100644 infra/bicep/modules/data/event-hub.bicep create mode 100644 infra/bicep/modules/data/postgresql-flexible-server.bicep create mode 100644 infra/bicep/modules/data/sql-database.bicep create mode 100644 infra/bicep/modules/data/storage-account.bicep create mode 100644 infra/bicep/modules/fabric/fabric-capacity.bicep create mode 100644 infra/bicep/modules/identity/cross-scope-role-assignment.bicep create mode 100644 infra/bicep/modules/identity/managed-identity.bicep create mode 100644 infra/bicep/modules/identity/role-assignments.bicep create mode 100644 infra/bicep/modules/monitoring/app-insights.bicep create mode 100644 infra/bicep/modules/monitoring/log-analytics.bicep create mode 100644 infra/bicep/modules/monitoring/portal-dashboard.bicep create mode 100644 infra/bicep/modules/security/key-vault.bicep diff --git a/infra/avm/modules/ai/ai-foundry-connection.bicep b/infra/avm/modules/ai/ai-foundry-connection.bicep new file mode 100644 index 00000000..c3260e4d --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry-connection.bicep @@ -0,0 +1,84 @@ +// ============================================================================ +// Module: AI Foundry Project Connection (Single) +// Description: Creates a single connection on an AI Foundry project. +// Generic, reusable — call once per connection type from main.bicep. +// Supports any connection category (CognitiveSearch, AzureBlob, +// AppInsights, RemoteTool, etc.) via parameterized properties. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name of the AI Foundry project.') +param projectName string + +@description('Required. Solution name suffix used to generate the connection name.') +param solutionName string + +@description('Optional. Connection name. Defaults to lowercase category with solution suffix.') +param connectionName string = toLower('${category}-connection-${solutionName}') + +@description('Required. Connection category (e.g., CognitiveSearch, AzureBlob, AppInsights, RemoteTool).') +param category string + +@description('Required. Connection target (URL or resource ID).') +param target string + +@description('Required. Authentication type (e.g., AAD, ApiKey, ProjectManagedIdentity).') +param authType string + +@description('Optional. Whether the connection is shared to all project users.') +param isSharedToAll bool = true + +@description('Optional. Whether this is the default connection for its category.') +param isDefault bool = false + +@description('Optional. Connection metadata object.') +param metadata object = {} + +@secure() +@description('Optional. Credentials key (for ApiKey auth type).') +param credentialsKey string = '' + +// ============================================================================ +// Existing Resource References +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: aiServicesAccount + name: projectName +} + +// ============================================================================ +// Connection +// ============================================================================ +var baseProperties = { + category: category + target: target + authType: authType + isSharedToAll: isSharedToAll + metadata: metadata +} + +var optionalDefault = isDefault ? { isDefault: true } : {} +var optionalCredentials = !empty(credentialsKey) ? { credentials: { key: credentialsKey } } : {} + +resource connection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-12-01' = { + parent: aiProject + name: connectionName + properties: any(union(baseProperties, optionalDefault, optionalCredentials)) +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Connection name.') +output connectionName string = connection.name + +@description('Connection resource ID.') +output connectionId string = connection.id diff --git a/infra/avm/modules/ai/ai-foundry-model-deployment.bicep b/infra/avm/modules/ai/ai-foundry-model-deployment.bicep new file mode 100644 index 00000000..1c534fd8 --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry-model-deployment.bicep @@ -0,0 +1,64 @@ +// ============================================================================ +// Module: Model Deployment +// Description: Deploys a single AI model to an existing AI Services account. +// Called repetitively from main.bicep for each model in the array. +// Generic, reusable across GSAs. +// ============================================================================ + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name for this model deployment.') +param deploymentName string + +@description('Optional. Model format (e.g., OpenAI).') +param modelFormat string = 'OpenAI' + +@description('Required. Model name (e.g., gpt-4o, text-embedding-ada-002).') +param modelName string + +@description('Optional. Model version. Empty string means latest.') +param modelVersion string = '' + +@description('Optional. RAI policy name.') +param raiPolicyName string = 'Microsoft.Default' + +@description('Required. SKU name (e.g., Standard, GlobalStandard).') +param skuName string + +@description('Required. SKU capacity (tokens per minute in thousands).') +param skuCapacity int + +// ============================================================================ +// Model Deployment +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource modelDeployment 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { + parent: aiServicesAccount + name: deploymentName + properties: { + model: { + format: modelFormat + name: modelName + version: !empty(modelVersion) ? modelVersion : null + } + raiPolicyName: raiPolicyName + } + sku: { + name: skuName + capacity: skuCapacity + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Name of the deployed model.') +output name string = modelDeployment.name + +@description('Resource ID of the model deployment.') +output resourceId string = modelDeployment.id diff --git a/infra/avm/modules/ai/ai-foundry-project.bicep b/infra/avm/modules/ai/ai-foundry-project.bicep new file mode 100644 index 00000000..76671e96 --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry-project.bicep @@ -0,0 +1,135 @@ +// ============================================================================ +// Module: AI Foundry Project (Account + Project) +// Description: AVM wrapper for Azure AI Services account creation and +// AI Foundry project provisioning. Generic, reusable across GSAs. +// AVM Module: avm/res/cognitive-services/account +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-openai +// ============================================================================ + +@description('Required. Solution name suffix used to generate resource names.') +param solutionName string + +@description('Optional. Override name for the AI Services account. Defaults to aif-{solutionName}.') +param name string = 'aif-${solutionName}' + +@description('Optional. Override name for the AI Foundry project. Defaults to proj-{solutionName}.') +param projectName string = 'proj-${solutionName}' + +@description('Required. Azure region for the resources.') +param location string + +@description('Optional. Tags to apply to resources.') +param tags object = {} + +@description('Optional. SKU name for the AI Services account.') +param skuName string = 'S0' + +@description('Optional. Whether to disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Optional. Whether to allow project management (AI Foundry hub).') +param allowProjectManagement bool = true + +@description('Optional. Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Managed identity type for the resources.') +@allowed(['SystemAssigned', 'UserAssigned', 'SystemAssigned, UserAssigned', 'None']) +param identityType string = 'SystemAssigned' + +@description('Optional. Network ACLs default action.') +@allowed(['Allow', 'Deny']) +param networkAclsDefaultAction string = 'Allow' + +// --- WAF: Monitoring --- +@description('Optional. Diagnostic settings for the resource.') +param diagnosticSettings array? + +// --- WAF: Telemetry --- +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- Role Assignments --- +@description('Optional. Array of role assignments to create on the AI Services account.') +param roleAssignments array? + +// ============================================================================ +// AI Services Account (AVM Module) +// ============================================================================ +module aiServicesAccount 'br/public:avm/res/cognitive-services/account:0.14.2' = { + name: take('avm.res.cognitive-services.account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: skuName + kind: 'AIServices' + disableLocalAuth: disableLocalAuth + allowProjectManagement: allowProjectManagement + customSubDomainName: name + networkAcls: { + defaultAction: networkAclsDefaultAction + virtualNetworkRules: [] + ipRules: [] + } + publicNetworkAccess: publicNetworkAccess + managedIdentities: { + systemAssigned: true + } + diagnosticSettings: diagnosticSettings + deployments: [] + roleAssignments: roleAssignments + // Private endpoints deployed separately to avoid AccountProvisioningStateInvalid + privateEndpoints: [] + } +} + +// ============================================================================ +// AI Foundry Project +// ============================================================================ +resource aiServicesResource 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name + dependsOn: [aiServicesAccount] +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { + parent: aiServicesResource + name: projectName + location: location + tags: tags + kind: 'AIServices' + identity: { + type: identityType + } + properties: {} + dependsOn: [aiServicesAccount] +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the AI Services account.') +output resourceId string = aiServicesAccount.outputs.resourceId + +@description('Name of the AI Services account.') +output name string = aiServicesAccount.outputs.name + +@description('Endpoint of the AI Services account.') +output endpoint string = aiServicesAccount.outputs.endpoint + +@description('System-assigned identity principal ID of the AI Services account.') +output principalId string = aiServicesAccount.outputs.systemAssignedMIPrincipalId + +@description('Resource ID of the AI Foundry project.') +output projectResourceId string = aiProject.id + +@description('Name of the AI Foundry project.') +output projectName string = aiProject.name + +@description('AI Foundry project endpoint.') +output projectEndpoint string = aiProject.properties.endpoints['AI Foundry API'] + +@description('System-assigned identity principal ID of the project.') +output projectIdentityPrincipalId string = aiProject.identity.principalId diff --git a/infra/avm/modules/ai/ai-foundry.bicep b/infra/avm/modules/ai/ai-foundry.bicep new file mode 100644 index 00000000..4342f5f9 --- /dev/null +++ b/infra/avm/modules/ai/ai-foundry.bicep @@ -0,0 +1,421 @@ +metadata name = 'Cognitive Services' +metadata description = 'This module deploys a Cognitive Service.' + +@description('Required. The name of Cognitive Services account.') +param name string + +@description('Optional: Name for the project which needs to be created.') +param projectName string + +@description('Optional: Description for the project which needs to be created.') +param projectDescription string + +param existingFoundryProjectResourceId string = '' + +@description('Required. Kind of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'AIServices' + 'AnomalyDetector' + 'CognitiveServices' + 'ComputerVision' + 'ContentModerator' + 'ContentSafety' + 'ConversationalLanguageUnderstanding' + 'CustomVision.Prediction' + 'CustomVision.Training' + 'Face' + 'FormRecognizer' + 'HealthInsights' + 'ImmersiveReader' + 'Internal.AllInOne' + 'LUIS' + 'LUIS.Authoring' + 'LanguageAuthoring' + 'MetricsAdvisor' + 'OpenAI' + 'Personalizer' + 'QnAMaker.v2' + 'SpeechServices' + 'TextAnalytics' + 'TextTranslation' +]) +param kind string + +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'C2' + 'C3' + 'C4' + 'F0' + 'F1' + 'S' + 'S0' + 'S1' + 'S10' + 'S2' + 'S3' + 'S4' + 'S5' + 'S6' + 'S7' + 'S8' + 'S9' +]) +param sku string = 'S0' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string? + +@description('Conditional. Subdomain name used for token-based authentication. Required if \'networkAcls\' or \'privateEndpoints\' are set.') +param customSubDomainName string? + +@description('Optional. A collection of rules governing the accessibility from specific network locations.') +param networkAcls object? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. List of allowed FQDN.') +param allowedFqdnList array? + +@description('Optional. The API properties for special APIs.') +param apiProperties object? + +@description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') +param disableLocalAuth bool = true + +import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The customer managed key definition.') +param customerManagedKey customerManagedKeyType? + +@description('Optional. The flag to enable dynamic throttling.') +param dynamicThrottlingEnabled bool = false + +@secure() +@description('Optional. Resource migration token.') +param migrationToken string? + +@description('Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists.') +param restore bool = false + +@description('Optional. Restrict outbound network access.') +param restrictOutboundNetworkAccess bool = true + +@description('Optional. The storage accounts for this resource.') +param userOwnedStorage array? + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityAllType? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Array of deployments about cognitive service accounts to create.') +param deployments deploymentType[]? + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +@description('Optional. Enable/Disable project management feature for AI Foundry.') +param allowProjectManagement bool? + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { + name: '46d3xbcp.res.cognitiveservices-account.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split(customerManagedKey.?keyVaultResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?keyVaultResourceId!, '/')[2], + split(customerManagedKey.?keyVaultResourceId!, '/')[4] + ) + + resource cMKKey 'keys@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName! + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[2], + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[4] + ) +} + +var useExistingService = !empty(existingFoundryProjectResourceId) + +resource cognitiveServiceNew 'Microsoft.CognitiveServices/accounts@2025-12-01' = if(!useExistingService) { + name: name + kind: kind + identity: identity + location: location + tags: tags + sku: { + name: sku + } + properties: { + allowProjectManagement: allowProjectManagement // allows project management for Cognitive Services accounts in AI Foundry - FDP updates + customSubDomainName: customSubDomainName + networkAcls: !empty(networkAcls ?? {}) + ? { + defaultAction: networkAcls.?defaultAction + virtualNetworkRules: networkAcls.?virtualNetworkRules ?? [] + ipRules: networkAcls.?ipRules ?? [] + } + : null + publicNetworkAccess: publicNetworkAccess != null + ? publicNetworkAccess + : (!empty(networkAcls) ? 'Enabled' : 'Disabled') + allowedFqdnList: allowedFqdnList + apiProperties: apiProperties + disableLocalAuth: disableLocalAuth + encryption: !empty(customerManagedKey) + ? { + keySource: 'Microsoft.KeyVault' + keyVaultProperties: { + identityClientId: !empty(customerManagedKey.?userAssignedIdentityResourceId ?? '') + ? cMKUserAssignedIdentity.properties.clientId + : null + keyVaultUri: cMKKeyVault.properties.vaultUri + keyName: customerManagedKey!.keyName + keyVersion: !empty(customerManagedKey.?keyVersion ?? '') + ? customerManagedKey!.?keyVersion + : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + } + } + : null + migrationToken: migrationToken + restore: restore + restrictOutboundNetworkAccess: restrictOutboundNetworkAccess + userOwnedStorage: userOwnedStorage + dynamicThrottlingEnabled: dynamicThrottlingEnabled + } +} + +var existingCognitiveServiceDetails = split(existingFoundryProjectResourceId, '/') + +resource cognitiveServiceExisting 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if(useExistingService) { + name: existingCognitiveServiceDetails[8] + scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) +} + +module cognitive_service_dependencies './modules/dependencies.bicep' = if(!useExistingService) { + params: { + projectName: projectName + projectDescription: projectDescription + name: cognitiveServiceNew.name + location: location + deployments: deployments + diagnosticSettings: diagnosticSettings + lock: lock + privateEndpoints: privateEndpoints + roleAssignments: roleAssignments + secretsExportConfiguration: secretsExportConfiguration + sku: sku + tags: tags + } +} + +module existing_cognitive_service_dependencies './modules/dependencies.bicep' = if(useExistingService) { + params: { + name: cognitiveServiceExisting.name + projectName: projectName + projectDescription: projectDescription + azureExistingAIProjectResourceId: existingFoundryProjectResourceId + location: location + deployments: deployments + diagnosticSettings: diagnosticSettings + lock: lock + privateEndpoints: privateEndpoints + roleAssignments: roleAssignments + secretsExportConfiguration: secretsExportConfiguration + sku: sku + tags: tags + } + scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) +} + +var cognitiveService = useExistingService ? cognitiveServiceExisting : cognitiveServiceNew + +@description('The name of the cognitive services account.') +output name string = useExistingService ? cognitiveServiceExisting.name : cognitiveServiceNew.name + +@description('The resource ID of the cognitive services account.') +output resourceId string = useExistingService ? cognitiveServiceExisting.id : cognitiveServiceNew.id + +@description('The resource group the cognitive services account was deployed into.') +output subscriptionId string = useExistingService ? existingCognitiveServiceDetails[2] : subscription().subscriptionId + +@description('The resource group the cognitive services account was deployed into.') +output resourceGroupName string = useExistingService ? existingCognitiveServiceDetails[4] : resourceGroup().name + +@description('The service endpoint of the cognitive services account.') +output endpoint string = useExistingService ? cognitiveServiceExisting.properties.endpoint : cognitiveService.properties.endpoint + +@description('All endpoints available for the cognitive services account, types depends on the cognitive service kind.') +output endpoints endpointType = useExistingService ? cognitiveServiceExisting.properties.endpoints : cognitiveService.properties.endpoints + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = useExistingService ? cognitiveServiceExisting.identity.principalId : cognitiveService.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = useExistingService ? cognitiveServiceExisting.location : cognitiveService.location + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.exportedSecrets : cognitive_service_dependencies.outputs.exportedSecrets + +@description('The private endpoints of the congitive services account.') +output privateEndpoints privateEndpointOutputType[] = useExistingService ? existing_cognitive_service_dependencies.outputs.privateEndpoints : cognitive_service_dependencies.outputs.privateEndpoints + +import { aiProjectOutputType } from './modules/project.bicep' +output aiProjectInfo aiProjectOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.aiProjectInfo : cognitive_service_dependencies.outputs.aiProjectInfo + +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for the private endpoint output.') +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The type for a cognitive services account deployment.') +type deploymentType = { + @description('Optional. Specify the name of cognitive service account deployment.') + name: string? + + @description('Required. Properties of Cognitive Services account deployment model.') + model: { + @description('Required. The name of Cognitive Services account deployment model.') + name: string + + @description('Required. The format of Cognitive Services account deployment model.') + format: string + + @description('Required. The version of Cognitive Services account deployment model.') + version: string + } + + @description('Optional. The resource model definition representing SKU.') + sku: { + @description('Required. The name of the resource model definition representing SKU.') + name: string + + @description('Optional. The capacity of the resource model definition representing SKU.') + capacity: int? + + @description('Optional. The tier of the resource model definition representing SKU.') + tier: string? + + @description('Optional. The size of the resource model definition representing SKU.') + size: string? + + @description('Optional. The family of the resource model definition representing SKU.') + family: string? + }? + + @description('Optional. The name of RAI policy.') + raiPolicyName: string? + + @description('Optional. The version upgrade option.') + versionUpgradeOption: string? +} + +@export() +@description('The type for a cognitive services account endpoint.') +type endpointType = { + @description('Type of the endpoint.') + name: string? + @description('The endpoint URI.') + endpoint: string? +} + +@export() +@description('The type of the secrets exported to the provided Key Vault.') +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The name for the accessKey1 secret to create.') + accessKey1Name: string? + + @description('Optional. The name for the accessKey2 secret to create.') + accessKey2Name: string? +} diff --git a/infra/avm/modules/ai/ai-search.bicep b/infra/avm/modules/ai/ai-search.bicep new file mode 100644 index 00000000..27f35bf6 --- /dev/null +++ b/infra/avm/modules/ai/ai-search.bicep @@ -0,0 +1,121 @@ +// ============================================================================ +// Module: AI Search +// Description: Deploys Azure AI Search with a two-step pattern: +// Step 1: Plain Bicep resource for fast initial creation (name, location, SKU) +// Step 2: AVM module update to enable managed identity & full configuration +// This reduces deployment time by making the resource available immediately +// while identity enablement proceeds separately. +// AVM Module: avm/res/search/search-service:0.12.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-cognitive-search +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +@minLength(3) +param solutionName string + +@description('Optional. Override name for the search service. Defaults to srch-{solutionName}.') +param name string = 'srch-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the search service.') +@allowed(['free', 'basic', 'standard', 'standard2', 'standard3', 'storage_optimized_l1', 'storage_optimized_l2']) +param skuName string = 'basic' + +@description('Number of replicas.') +param replicaCount int = 1 + +@description('Number of partitions.') +param partitionCount int = 1 + +@description('Hosting mode.') +@allowed(['Default', 'HighDensity']) +param hostingMode string = 'Default' + +@description('Semantic search tier.') +@allowed(['disabled', 'free', 'standard']) +param semanticSearch string = 'free' + +@description('Whether to disable local authentication.') +param disableLocalAuth bool = true + +@description('Managed identity type for the search service.') +param managedIdentityType string = 'SystemAssigned' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// --- WAF: Telemetry --- +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Private endpoint configurations.') +param privateEndpoints array = [] + +// --- Role Assignments --- +@description('Optional. Array of role assignments to create on the AI Search service.') +param roleAssignments array = [] + +// ============================================================================ +// Step 1: Initial resource creation (plain Bicep — fast) +// ============================================================================ +resource searchService 'Microsoft.Search/searchServices@2025-05-01' = { + name: name + location: location + sku: { + name: skuName + } +} + +// ============================================================================ +// Step 2: AVM update — enables identity & full configuration +// ============================================================================ +module searchServiceUpdate 'br/public:avm/res/search/search-service:0.12.0' = { + name: take('avm.res.search.update.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: skuName + replicaCount: replicaCount + partitionCount: partitionCount + hostingMode: hostingMode + semanticSearch: semanticSearch + disableLocalAuth: disableLocalAuth + publicNetworkAccess: publicNetworkAccess + managedIdentities: { + systemAssigned: managedIdentityType == 'SystemAssigned' + } + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + privateEndpoints: privateEndpoints + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + } + dependsOn: [ + searchService + ] +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the AI Search service.') +output resourceId string = searchService.id + +@description('Name of the AI Search service.') +output name string = searchService.name + +@description('Endpoint URL of the AI Search service.') +output endpoint string = 'https://${searchService.name}.search.windows.net' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = searchServiceUpdate.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/ai/ai-services.bicep b/infra/avm/modules/ai/ai-services.bicep new file mode 100644 index 00000000..7e27f49d --- /dev/null +++ b/infra/avm/modules/ai/ai-services.bicep @@ -0,0 +1,121 @@ +// ============================================================================ +// Module: Azure AI Services (Generic) +// Description: AVM wrapper for Cognitive Services — supports Content Safety, +// Speech, Computer Vision, Document Intelligence, and others. +// AVM Module: avm/res/cognitive-services/account:0.14.2 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name prefix for the resource (e.g., cs, speech, cv, docintel).') +param namePrefix string + +@description('The kind of Cognitive Service to deploy.') +@allowed([ + 'ContentSafety' + 'SpeechServices' + 'ComputerVision' + 'FormRecognizer' + 'TextAnalytics' + 'TextTranslation' + 'Face' + 'OpenAI' + 'AIServices' +]) +param kind string + +@description('Optional. Override name for the resource. Defaults to {namePrefix}-{solutionName}.') +param name string = '${namePrefix}-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = false + +@description('SKU for the Cognitive Services account.') +@allowed(['F0', 'S0', 'S1']) +param sku string = 'S0' + +@description('Custom subdomain name for the account.') +param customSubDomainName string = '' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Optional. Role assignments for the resource.') +param roleAssignments array = [] + +var effectiveSubDomain = !empty(customSubDomainName) ? customSubDomainName : name + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module aiService 'br/public:avm/res/cognitive-services/account:0.14.2' = { + name: take('avm.res.cognitive-services.${namePrefix}.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + kind: kind + sku: sku + customSubDomainName: effectiveSubDomain + disableLocalAuth: disableLocalAuth + managedIdentities: { systemAssigned: true } + publicNetworkAccess: publicNetworkAccess + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'account' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AI Services account.') +output name string = aiService.outputs.name + +@description('Resource ID of the AI Services account.') +output resourceId string = aiService.outputs.resourceId + +@description('Endpoint of the AI Services account.') +output endpoint string = aiService.outputs.endpoint + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = aiService.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/ai/existing-project-setup.bicep b/infra/avm/modules/ai/existing-project-setup.bicep new file mode 100644 index 00000000..7a396dcb --- /dev/null +++ b/infra/avm/modules/ai/existing-project-setup.bicep @@ -0,0 +1,50 @@ +// ============================================================================ +// Module: Existing AI Foundry Project Reference +// Description: References an existing AI Services account and project to +// retrieve their identities. No deployments, no connections. +// Use generic ai-foundry-connection and ai-foundry-model-deployment +// modules for those concerns. +// ============================================================================ + +@description('Required. The name of the existing Cognitive Services account.') +param name string + +@description('Required. The name of the existing AI project.') +param projectName string + +// ============================================================================ +// Existing Resource References +// ============================================================================ +resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: cognitiveService + name: projectName +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The principal ID of the AI Foundry system-assigned managed identity (empty if none).') +output aiFoundryPrincipalId string = cognitiveService.identity.?principalId ?? '' + +@description('The principal ID of the AI Project system-assigned managed identity (empty if none).') +output aiProjectPrincipalId string = aiProject.identity.?principalId ?? '' + +@description('The name of the AI Services account.') +output aiServicesAccountName string = cognitiveService.name + +@description('The name of the AI project.') +output aiProjectName string = aiProject.name + +@description('The endpoint URL for the Azure OpenAI service.') +output aiFoundryEndpoint string = 'https://${name}.openai.azure.com/' + +@description('The endpoint URL for the AI Foundry project.') +output projectEndpoint string = 'https://${name}.services.ai.azure.com/api/projects/${projectName}' + +@description('The resource ID of the AI Services account.') +output aiFoundryResourceId string = cognitiveService.id + diff --git a/infra/avm/modules/ai/modules/dependencies.bicep b/infra/avm/modules/ai/modules/dependencies.bicep new file mode 100644 index 00000000..55bb9ff7 --- /dev/null +++ b/infra/avm/modules/ai/modules/dependencies.bicep @@ -0,0 +1,479 @@ +@description('Required. The name of Cognitive Services account.') +param name string + +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'C2' + 'C3' + 'C4' + 'F0' + 'F1' + 'S' + 'S0' + 'S1' + 'S10' + 'S2' + 'S3' + 'S4' + 'S5' + 'S6' + 'S7' + 'S8' + 'S9' +]) +param sku string = 'S0' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Array of deployments about cognitive service accounts to create.') +param deployments deploymentType[]? + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional: Name for the project which needs to be created.') +param projectName string + +@description('Optional: Description for the project which needs to be created.') +param projectDescription string + +@description('Optional: Provide the existing project resource id in case if it needs to be reused') +param azureExistingAIProjectResourceId string = '' + +var builtInRoleNames = { + 'Cognitive Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68' + ) + 'Cognitive Services Custom Vision Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3' + ) + 'Cognitive Services Custom Vision Deployment': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5c4089e1-6d96-4d2f-b296-c1bc7137275f' + ) + 'Cognitive Services Custom Vision Labeler': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '88424f51-ebe7-446f-bc41-7fa16989e96c' + ) + 'Cognitive Services Custom Vision Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '93586559-c37d-4a6b-ba08-b9f0940c2d73' + ) + 'Cognitive Services Custom Vision Trainer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b' + ) + 'Cognitive Services Data Reader (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b59867f0-fa02-499b-be73-45a86b5b3e1c' + ) + 'Cognitive Services Face Recognizer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '9894cab4-e18a-44aa-828b-cb588cd6f2d7' + ) + 'Cognitive Services Immersive Reader User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b2de6794-95db-4659-8781-7e080d3f2b9d' + ) + 'Cognitive Services Language Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f07febfe-79bc-46b1-8b37-790e26e6e498' + ) + 'Cognitive Services Language Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7628b7b8-a8b2-4cdc-b46f-e9b35248918e' + ) + 'Cognitive Services Language Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8' + ) + 'Cognitive Services LUIS Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f72c8140-2111-481c-87ff-72b910f6e3f8' + ) + 'Cognitive Services LUIS Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18e81cdc-4e98-4e29-a639-e7d10c5a6226' + ) + 'Cognitive Services LUIS Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '6322a993-d5c9-4bed-b113-e49bbea25b27' + ) + 'Cognitive Services Metrics Advisor Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'cb43c632-a144-4ec5-977c-e80c4affc34a' + ) + 'Cognitive Services Metrics Advisor User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3b20f47b-3825-43cb-8114-4bd2201156a8' + ) + 'Cognitive Services OpenAI Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a001fd3d-188f-4b5d-821b-7da978bf7442' + ) + 'Cognitive Services OpenAI User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + ) + 'Cognitive Services QnA Maker Editor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f4cc2bf9-21be-47a1-bdf1-5c5804381025' + ) + 'Cognitive Services QnA Maker Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '466ccd10-b268-4a11-b098-b4849f024126' + ) + 'Cognitive Services Speech Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0e75ca1e-0464-4b4d-8b93-68208a576181' + ) + 'Cognitive Services Speech User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2dc8367-1007-4938-bd23-fe263f013447' + ) + 'Cognitive Services User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a97b65f3-24c7-4388-baec-2e87135dc908' + ) + 'Azure AI Developer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '64702f94-c441-49e6-a78b-ef80e0188fee' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +var enableReferencedModulesTelemetry = false + +resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name +} + +@batchSize(1) +resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = [ + for (deployment, index) in (deployments ?? []): { + parent: cognitiveService + name: deployment.?name ?? '${name}-deployments' + properties: { + model: deployment.model + raiPolicyName: deployment.?raiPolicyName + versionUpgradeOption: deployment.?versionUpgradeOption + } + sku: deployment.?sku ?? { + name: sku + capacity: sku.?capacity + tier: sku.?tier + size: sku.?size + family: sku.?family + } + } +] + +resource cognitiveService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: cognitiveService +} + +resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: cognitiveService + } +] + +module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.12.0' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}' + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: enableReferencedModulesTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: cognitiveService + } +] + +module secretsExport './keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[2], + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId!, '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'accessKey1Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey1Name + value: cognitiveService.listKeys().key1 + } + ] + : [], + contains(secretsExportConfiguration!, 'accessKey2Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey2Name + value: cognitiveService.listKeys().key2 + } + ] + : [] + ) + } +} + +module aiProject 'project.bicep' = if(!empty(projectName) || !empty(azureExistingAIProjectResourceId)) { + name: take('${name}-ai-project-${projectName}-deployment', 64) + params: { + name: projectName + desc: projectDescription + aiServicesName: cognitiveService.name + location: location + tags: tags + azureExistingAIProjectResourceId: azureExistingAIProjectResourceId + } +} + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + +@description('The private endpoints of the congitive services account.') +output privateEndpoints privateEndpointOutputType[] = [ + for (pe, index) in (privateEndpoints ?? []): { + name: cognitiveService_privateEndpoints[index].outputs.name + resourceId: cognitiveService_privateEndpoints[index].outputs.resourceId + groupId: cognitiveService_privateEndpoints[index].outputs.?groupId! + customDnsConfigs: cognitiveService_privateEndpoints[index].outputs.customDnsConfigs + networkInterfaceResourceIds: cognitiveService_privateEndpoints[index].outputs.networkInterfaceResourceIds + } +] + +import { aiProjectOutputType } from 'project.bicep' +output aiProjectInfo aiProjectOutputType = aiProject.outputs.aiProjectInfo + +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for the private endpoint output.') +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The type for a cognitive services account deployment.') +type deploymentType = { + @description('Optional. Specify the name of cognitive service account deployment.') + name: string? + + @description('Required. Properties of Cognitive Services account deployment model.') + model: { + @description('Required. The name of Cognitive Services account deployment model.') + name: string + + @description('Required. The format of Cognitive Services account deployment model.') + format: string + + @description('Required. The version of Cognitive Services account deployment model.') + version: string + } + + @description('Optional. The resource model definition representing SKU.') + sku: { + @description('Required. The name of the resource model definition representing SKU.') + name: string + + @description('Optional. The capacity of the resource model definition representing SKU.') + capacity: int? + + @description('Optional. The tier of the resource model definition representing SKU.') + tier: string? + + @description('Optional. The size of the resource model definition representing SKU.') + size: string? + + @description('Optional. The family of the resource model definition representing SKU.') + family: string? + }? + + @description('Optional. The name of RAI policy.') + raiPolicyName: string? + + @description('Optional. The version upgrade option.') + versionUpgradeOption: string? +} + +@export() +@description('The type for a cognitive services account endpoint.') +type endpointType = { + @description('Type of the endpoint.') + name: string? + @description('The endpoint URI.') + endpoint: string? +} + +@export() +@description('The type of the secrets exported to the provided Key Vault.') +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The name for the accessKey1 secret to create.') + accessKey1Name: string? + + @description('Optional. The name for the accessKey2 secret to create.') + accessKey2Name: string? +} diff --git a/infra/avm/modules/ai/modules/keyVaultExport.bicep b/infra/avm/modules/ai/modules/keyVaultExport.bicep new file mode 100644 index 00000000..ccbcf14b --- /dev/null +++ b/infra/avm/modules/ai/modules/keyVaultExport.bicep @@ -0,0 +1,43 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the secrets in.') +param keyVaultName string + +import { secretToSetType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2026-02-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // + +import { secretSetOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetOutputType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + secretUriWithVersion: secrets[index].properties.secretUriWithVersion + } +] diff --git a/infra/avm/modules/ai/modules/project.bicep b/infra/avm/modules/ai/modules/project.bicep new file mode 100644 index 00000000..3a1620d2 --- /dev/null +++ b/infra/avm/modules/ai/modules/project.bicep @@ -0,0 +1,62 @@ +@description('Required. Name of the AI Services project.') +param name string + +@description('Required. The location of the Project resource.') +param location string = resourceGroup().location + +@description('Optional. The description of the AI Foundry project to create. Defaults to the project name.') +param desc string = name + +@description('Required. Name of the existing Cognitive Services resource to create the AI Foundry project in.') +param aiServicesName string + +@description('Optional. Tags to be applied to the resources.') +param tags object = {} + +@description('Optional. Use this parameter to use an existing AI project resource ID from different resource group') +param azureExistingAIProjectResourceId string = '' + +// // Extract components from existing AI Project Resource ID if provided +var useExistingProject = !empty(azureExistingAIProjectResourceId) +var existingProjName = useExistingProject ? last(split(azureExistingAIProjectResourceId, '/')) : '' +var existingProjEndpoint = useExistingProject ? format('https://{0}.services.ai.azure.com/api/projects/{1}', aiServicesName, existingProjName) : '' + +// Reference to cognitive service in current resource group for new projects +resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesName +} + +// Create new AI project only if not reusing existing one +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = if(!useExistingProject) { + parent: cogServiceReference + name: name + tags: tags + location: location + identity: { + type: 'SystemAssigned' + } + properties: { + description: desc + displayName: name + } +} + +@description('AI Project metadata including name, resource ID, and API endpoint.') +output aiProjectInfo aiProjectOutputType = { + name: useExistingProject ? existingProjName : aiProject.name + resourceId: useExistingProject ? azureExistingAIProjectResourceId : aiProject.id + apiEndpoint: useExistingProject ? existingProjEndpoint : aiProject.properties.endpoints['AI Foundry API'] +} + +@export() +@description('Output type representing AI project information.') +type aiProjectOutputType = { + @description('Required. Name of the AI project.') + name: string + + @description('Required. Resource ID of the AI project.') + resourceId: string + + @description('Required. API endpoint for the AI project.') + apiEndpoint: string +} diff --git a/infra/avm/modules/compute/app-service-plan.bicep b/infra/avm/modules/compute/app-service-plan.bicep new file mode 100644 index 00000000..6e9e72d0 --- /dev/null +++ b/infra/avm/modules/compute/app-service-plan.bicep @@ -0,0 +1,67 @@ +// ============================================================================ +// Module: App Service Plan +// Description: AVM wrapper for Azure App Service Plan +// AVM Module: avm/res/web/serverfarm:0.7.0 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service Plan.') +param name string = 'asp-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the App Service Plan.') +@allowed(['F1', 'D1', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1', 'P2', 'P3', 'P4', 'P0v3', 'P0v4', 'P1v3', 'P1v4', 'P2v3', 'P3v3']) +param skuName string = 'B2' + +@description('Whether the plan is Linux-based.') +param reserved bool = true + +@description('Kind of the App Service Plan.') +param kind string = 'linux' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Number of instances (workers).') +param skuCapacity int = 1 + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Enable zone redundancy. Requires Premium SKU (P1v3+).') +param zoneRedundant bool = false + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module appServicePlan 'br/public:avm/res/web/serverfarm:0.7.0' = { + name: take('avm.res.web.serverfarm.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + skuCapacity: skuCapacity + reserved: reserved + kind: kind + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + zoneRedundant: zoneRedundant + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service Plan.') +output resourceId string = appServicePlan.outputs.resourceId + +@description('Name of the App Service Plan.') +output name string = appServicePlan.outputs.name diff --git a/infra/avm/modules/compute/app-service.bicep b/infra/avm/modules/compute/app-service.bicep new file mode 100644 index 00000000..a41f96f5 --- /dev/null +++ b/infra/avm/modules/compute/app-service.bicep @@ -0,0 +1,115 @@ +// ============================================================================ +// Module: App Service +// Description: AVM wrapper for Azure App Service (Web App) +// AVM Module: avm/res/web/site:0.23.1 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service.') +param name string = solutionName + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Docker image name (e.g., DOCKER|registry.azurecr.io/image:tag).') +param linuxFxVersion string + +@description('Application settings key-value pairs.') +param appSettings object = {} + +@description('Whether to enable Always On.') +param alwaysOn bool = true + +@description('Kind of web app.') +param kind string = 'app,linux' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Subnet resource ID for VNet integration.') +param virtualNetworkSubnetId string = '' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module appService 'br/public:avm/res/web/site:0.23.1' = { + name: take('avm.res.web.site.${name}', 64) + params: { + name: name + location: location + tags: tags + kind: kind + enableTelemetry: enableTelemetry + serverFarmResourceId: serverFarmResourceId + managedIdentities: { + systemAssigned: true + } + siteConfig: { + alwaysOn: alwaysOn + ftpsState: 'Disabled' + linuxFxVersion: linuxFxVersion + minTlsVersion: '1.2' + } + e2eEncryptionEnabled: true + configs: [ + { + name: 'appsettings' + properties: appSettings + } + { + name: 'logs' + properties: { + applicationLogs: { fileSystem: { level: 'Verbose' } } + detailedErrorMessages: { enabled: true } + failedRequestsTracing: { enabled: true } + httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } } + } + } + ] + publicNetworkAccess: publicNetworkAccess + virtualNetworkSubnetResourceId: !empty(virtualNetworkSubnetId) ? virtualNetworkSubnetId : null + basicPublishingCredentialsPolicies: [ + { + name: 'ftp' + allow: false + } + { + name: 'scm' + allow: false + } + ] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service.') +output resourceId string = appService.outputs.resourceId + +@description('Name of the App Service.') +output name string = appService.outputs.name + +@description('Default hostname of the App Service.') +output defaultHostname string = appService.outputs.defaultHostname + +@description('URL of the App Service.') +output appUrl string = 'https://${appService.outputs.defaultHostname}' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = appService.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/compute/container-app-environment.bicep b/infra/avm/modules/compute/container-app-environment.bicep new file mode 100644 index 00000000..1f488eed --- /dev/null +++ b/infra/avm/modules/compute/container-app-environment.bicep @@ -0,0 +1,95 @@ +// ============================================================================ +// Module: Azure Container Apps Environment (AVM) +// AVM Module: avm/res/app/managed-environment:0.13.3 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Container Apps Environment.') +param name string = 'cae-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace (required when enableMonitoring is true).') +param logAnalyticsWorkspaceResourceId string = '' + +@description('Subnet resource ID for VNet integration (required when enablePrivateNetworking is true).') +param infrastructureSubnetId string = '' + +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('Enable private networking (internal environment, public access disabled).') +param enablePrivateNetworking bool = false + +@description('Enable monitoring (Log Analytics + App Insights).') +param enableMonitoring bool = true + +@description('Application Insights connection string (optional, for App Insights integration).') +param appInsightsConnectionString string = '' + +@description('Enable redundancy (dedicated workload profiles + infra resource group).') +param enableRedundancy bool = false + +@description('Infrastructure resource group name (used when zone redundancy is enabled). Defaults to "{resourceGroup}-infra" if empty.') +param infrastructureResourceGroupName string = '${resourceGroup().name}-infra' + +@description('Workload profiles configuration (e.g., Consumption or dedicated D4 profiles).') +param workloadProfiles array = [ + { + name: 'Consumption' + workloadProfileType: 'Consumption' + } +] + +// ============================================================================ +// Container Apps Environment (AVM) +// ============================================================================ +module managedEnvironment 'br/public:avm/res/app/managed-environment:0.13.3' = { + name: take('avm.res.app.managedenvironment.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + // WAF: Private networking + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + internal: enablePrivateNetworking + infrastructureSubnetResourceId: !empty(infrastructureSubnetId) ? infrastructureSubnetId : null + // WAF: Monitoring + appLogsConfiguration: enableMonitoring && !empty(logAnalyticsWorkspaceResourceId) + ? { + destination: 'log-analytics' + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + } + : null + appInsightsConnectionString: !empty(appInsightsConnectionString) ? appInsightsConnectionString : null + // WAF: Redundancy + zoneRedundant: zoneRedundant || enableRedundancy + infrastructureResourceGroupName: !empty(infrastructureResourceGroupName) ? infrastructureResourceGroupName : null + workloadProfiles: workloadProfiles + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the Container Apps Environment.') +output name string = managedEnvironment.outputs.name + +@description('The resource ID of the Container Apps Environment.') +output resourceId string = managedEnvironment.outputs.resourceId + +@description('The default domain of the Container Apps Environment.') +output defaultDomain string = managedEnvironment.outputs.defaultDomain + +@description('The static IP of the Container Apps Environment.') +output staticIp string = managedEnvironment.outputs.staticIp diff --git a/infra/avm/modules/compute/container-app.bicep b/infra/avm/modules/compute/container-app.bicep new file mode 100644 index 00000000..07e7b4f9 --- /dev/null +++ b/infra/avm/modules/compute/container-app.bicep @@ -0,0 +1,105 @@ +// ============================================================================ +// Module: Azure Container App (AVM) +// AVM Module: avm/res/app/container-app:0.22.1 +// ============================================================================ + +@description('Name of the container app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Container Apps Environment.') +param environmentResourceId string + +@description('Container definitions.') +param containers array + +@description('Enable external ingress.') +param ingressExternal bool = true + +@description('Target port for ingress.') +param ingressTargetPort int = 80 + +@description('Ingress transport protocol.') +@allowed(['auto', 'http', 'http2', 'tcp']) +param ingressTransport string = 'auto' + +@description('Whether to allow insecure ingress connections.') +param ingressAllowInsecure bool = false + +@description('Disable ingress entirely (for background workers).') +param disableIngress bool = false + +@description('Container registry configurations.') +param registries array? + +@description('Secret definitions.') +param secrets array? + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('CORS policy configuration.') +param corsPolicy object = {} + +@description('Active revision mode.') +@allowed(['Single', 'Multiple']) +param activeRevisionsMode string = 'Single' + +@description('Scale settings (maxReplicas, minReplicas, rules, cooldownPeriod, pollingInterval).') +param scaleSettings object = { + maxReplicas: 10 + minReplicas: 0 +} + +@description('Workload profile name.') +param workloadProfileName string? + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Container App (AVM) +// ============================================================================ +module containerApp 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.containerapp.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + environmentResourceId: environmentResourceId + containers: containers + ingressExternal: disableIngress ? false : ingressExternal + ingressTargetPort: ingressTargetPort + ingressTransport: ingressTransport + ingressAllowInsecure: ingressAllowInsecure + disableIngress: disableIngress + registries: registries + secrets: secrets + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + corsPolicy: !empty(corsPolicy) ? corsPolicy : null + activeRevisionsMode: activeRevisionsMode + scaleSettings: scaleSettings + workloadProfileName: workloadProfileName + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container app.') +output name string = containerApp.outputs.name + +@description('The resource ID of the container app.') +output resourceId string = containerApp.outputs.resourceId + +@description('The FQDN of the container app.') +output fqdn string = containerApp.outputs.fqdn + +@description('System-assigned identity principal ID.') +output principalId string = containerApp.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/compute/container-instance.bicep b/infra/avm/modules/compute/container-instance.bicep new file mode 100644 index 00000000..c840be20 --- /dev/null +++ b/infra/avm/modules/compute/container-instance.bicep @@ -0,0 +1,120 @@ +// ============================================================================ +// Module: Azure Container Instance (AVM) +// AVM Module: avm/res/container-instance/container-group:0.7.0 +// ============================================================================ + +@description('Name of the container group.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Container image to deploy.') +param containerImage string + +@description('CPU cores for the container.') +param cpu int = 2 + +@description('Memory in GB for the container.') +param memoryInGB int = 4 + +@description('Port to expose.') +param port int = 8000 + +@description('Environment variables for the container.') +param environmentVariables array = [] + +@description('Operating system type.') +@allowed(['Linux', 'Windows']) +param osType string = 'Linux' + +@description('Restart policy.') +@allowed(['Always', 'OnFailure', 'Never']) +param restartPolicy string = 'Always' + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Image registry credentials.') +param imageRegistryCredentials array = [] + +@description('Subnet resource ID for VNet integration. If empty, public IP is used.') +param subnetResourceId string = '' + +@description('Availability zone for the container group. Use -1 for no zone.') +param availabilityZone int = -1 + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Variables +// ============================================================================ +var isPrivateNetworking = !empty(subnetResourceId) + +var containers = [ + { + name: name + properties: { + image: containerImage + resources: { + requests: { + cpu: cpu + memoryInGB: string(memoryInGB) + } + } + ports: [ + { + port: port + protocol: 'TCP' + } + ] + environmentVariables: environmentVariables + } + } +] + +// ============================================================================ +// Container Instance (AVM) +// ============================================================================ +module containerGroup 'br/public:avm/res/container-instance/container-group:0.7.0' = { + name: take('avm.res.containerinstance.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + containers: containers + osType: osType + restartPolicy: restartPolicy + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + ipAddress: { + type: isPrivateNetworking ? 'Private' : 'Public' + ports: [ + { + port: port + protocol: 'TCP' + } + ] + dnsNameLabel: isPrivateNetworking ? null : name + } + imageRegistryCredentials: !empty(imageRegistryCredentials) ? imageRegistryCredentials : [] + subnets: isPrivateNetworking ? [{ subnetResourceId: subnetResourceId }] : [] + availabilityZone: availabilityZone + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container group.') +output name string = containerGroup.outputs.name + +@description('The resource ID of the container group.') +output resourceId string = containerGroup.outputs.resourceId + +@description('The IP address of the container group.') +output ipAddress string = containerGroup.outputs.?iPv4Address ?? '' diff --git a/infra/avm/modules/compute/container-registry.bicep b/infra/avm/modules/compute/container-registry.bicep new file mode 100644 index 00000000..b3e0180f --- /dev/null +++ b/infra/avm/modules/compute/container-registry.bicep @@ -0,0 +1,104 @@ +// ============================================================================ +// Module: Azure Container Registry (AVM) +// AVM Module: avm/res/container-registry/registry:0.12.1 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the container registry.') +param name string = replace('cr${solutionName}', '-', '') + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the container registry.') +@allowed(['Basic', 'Standard', 'Premium']) +param sku string = 'Premium' + +@description('Enable admin user for the registry.') +param adminUserEnabled bool = false + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Export policy status. Must be "enabled" when publicNetworkAccess is "Enabled".') +param exportPolicyStatus string = 'enabled' + +@description('Principal IDs to assign AcrPull role.') +param acrPullPrincipalIds array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for private endpoint.') +param privateDnsZoneResourceIds array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Role Assignments +// ============================================================================ +var acrPullRoleId = '7f951dda-4ed3-4680-a7ca-43fe172d538d' + +var roleAssignments = [for principalId in acrPullPrincipalIds: { + principalId: principalId + roleDefinitionIdOrName: acrPullRoleId + principalType: 'ServicePrincipal' +}] + +// ============================================================================ +// Private Endpoint Config +// ============================================================================ +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +// ============================================================================ +// Container Registry (AVM) +// ============================================================================ +module containerRegistry 'br/public:avm/res/container-registry/registry:0.12.1' = { + name: take('avm.res.containerregistry.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + acrSku: sku + acrAdminUserEnabled: adminUserEnabled + publicNetworkAccess: publicNetworkAccess + exportPolicyStatus: exportPolicyStatus + roleAssignments: !empty(acrPullPrincipalIds) ? roleAssignments : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container registry.') +output name string = containerRegistry.outputs.name + +@description('The login server URL.') +output loginServer string = containerRegistry.outputs.loginServer + +@description('The resource ID of the container registry.') +output resourceId string = containerRegistry.outputs.resourceId diff --git a/infra/avm/modules/compute/function-app.bicep b/infra/avm/modules/compute/function-app.bicep new file mode 100644 index 00000000..f6d84945 --- /dev/null +++ b/infra/avm/modules/compute/function-app.bicep @@ -0,0 +1,95 @@ +// ============================================================================ +// Module: Azure Function App (AVM) +// AVM Module: avm/res/web/site:0.23.1 +// ============================================================================ + +@description('Name of the function app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Resource ID of the storage account for function app.') +param storageAccountResourceId string + +@description('Name of the storage account.') +param storageAccountName string + +@description('Managed identity configuration.') +param managedIdentities object = { + systemAssigned: true +} + +@description('App settings as name-value pairs.') +param appSettings array = [] + +@description('Site configuration object.') +param siteConfig object = {} + +@description('Runtime stack.') +param runtimeStack string = 'python' + +@description('Runtime version.') +param runtimeVersion string = '3.11' + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Variables +// ============================================================================ +var baseAppSettings = { + AzureWebJobsStorage__accountName: storageAccountName + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: runtimeStack +} + +var customAppSettings = reduce(appSettings, {}, (cur, next) => union(cur, { '${next.name}': next.value })) +var mergedAppSettings = union(baseAppSettings, customAppSettings) + +// ============================================================================ +// Function App (AVM) +// ============================================================================ +module functionApp 'br/public:avm/res/web/site:0.23.1' = { + name: take('avm.res.web.site.func.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + kind: 'functionapp,linux' + serverFarmResourceId: serverFarmResourceId + storageAccountRequired: false + managedIdentities: managedIdentities + configs: [ + { + name: 'appsettings' + properties: mergedAppSettings + } + ] + siteConfig: union({ + linuxFxVersion: '${toUpper(runtimeStack)}|${runtimeVersion}' + }, siteConfig) + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the function app.') +output name string = functionApp.outputs.name + +@description('The resource ID of the function app.') +output resourceId string = functionApp.outputs.resourceId + +@description('The default hostname of the function app.') +output defaultHostName string = functionApp.outputs.defaultHostname + +@description('The principal ID of the system-assigned managed identity.') +output principalId string = functionApp.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/compute/kubernetes.bicep b/infra/avm/modules/compute/kubernetes.bicep new file mode 100644 index 00000000..54053dd4 --- /dev/null +++ b/infra/avm/modules/compute/kubernetes.bicep @@ -0,0 +1,158 @@ +// ============================================================================ +// Module: Azure Kubernetes Service (AKS) +// Description: AVM wrapper for Azure Kubernetes Service Managed Cluster +// AVM Module: avm/res/container-service/managed-cluster:0.13.1 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the AKS cluster.') +param name string = 'aks-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Kubernetes version for the cluster.') +param kubernetesVersion string = '1.34' + +@description('Agent pool configurations. Each entry requires name, vmSize, count, mode (System/User).') +param agentPools array = [ + { + name: 'agentpool' + vmSize: 'Standard_D4ds_v5' + count: 2 + minCount: 1 + maxCount: 2 + enableAutoScaling: true + osType: 'Linux' + mode: 'System' + type: 'VirtualMachineScaleSets' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + } +] + +@description('Enable Kubernetes RBAC.') +param enableRBAC bool = true + +@description('Disable local accounts (enforce AAD-only).') +param disableLocalAccounts bool = false + +@description('Network plugin for the cluster.') +@allowed(['azure', 'kubenet', 'none']) +param networkPlugin string = 'azure' + +@description('Network policy for the cluster.') +@allowed(['azure', 'calico', '']) +param networkPolicy string = 'azure' + +@description('DNS prefix for the cluster.') +param dnsPrefix string = '' + +@description('SKU tier for the cluster.') +@allowed(['Free', 'Standard', 'Premium']) +param skuTier string = 'Standard' + +@description('Service CIDR for Kubernetes services.') +param serviceCidr string = '10.20.0.0/16' + +@description('DNS service IP (must be within serviceCidr).') +param dnsServiceIP string = '10.20.0.10' + +@description('Auto-upgrade channel for the cluster.') +@allowed(['none', 'patch', 'rapid', 'stable', 'node-image']) +param autoUpgradeChannel string = 'stable' + +@description('Log Analytics workspace resource ID for monitoring.') +param logAnalyticsWorkspaceResourceId string = '' + +// --- WAF: Networking --- +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Enable private cluster (API server not publicly accessible).') +param enablePrivateCluster bool = false + +@description('Subnet resource ID for the agent pool (for VNet integration).') +param agentPoolSubnetId string = '' + +@description('Enable Microsoft Defender for Containers.') +param enableDefender bool = false + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Role assignments for the cluster.') +param roleAssignments array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// Variables +// ============================================================================ +var effectiveDnsPrefix = !empty(dnsPrefix) ? dnsPrefix : name +var enableMonitoring = !empty(logAnalyticsWorkspaceResourceId) + +var effectiveAgentPools = [for pool in agentPools: union(pool, !empty(agentPoolSubnetId) ? { vnetSubnetResourceId: agentPoolSubnetId } : {})] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module aksCluster 'br/public:avm/res/container-service/managed-cluster:0.13.1' = { + name: take('avm.res.container-service.managed-cluster.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + kubernetesVersion: kubernetesVersion + primaryAgentPoolProfiles: effectiveAgentPools + enableRBAC: enableRBAC + disableLocalAccounts: disableLocalAccounts + networkPlugin: networkPlugin + networkPolicy: networkPolicy + dnsPrefix: effectiveDnsPrefix + skuTier: skuTier + serviceCidr: serviceCidr + dnsServiceIP: dnsServiceIP + publicNetworkAccess: publicNetworkAccess + apiServerAccessProfile: { + enablePrivateCluster: enablePrivateCluster + } + autoUpgradeProfile: { + upgradeChannel: autoUpgradeChannel + nodeOSUpgradeChannel: 'Unmanaged' + } + managedIdentities: { systemAssigned: true } + omsAgentEnabled: enableMonitoring + monitoringWorkspaceResourceId: enableMonitoring ? logAnalyticsWorkspaceResourceId : null + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + securityProfile: enableDefender && enableMonitoring ? { + defender: { + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + securityMonitoring: { + enabled: true + } + } + } : {} + roleAssignments: roleAssignments + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AKS cluster.') +output name string = aksCluster.outputs.name + +@description('Resource ID of the AKS cluster.') +output resourceId string = aksCluster.outputs.resourceId + +@description('FQDN of the AKS cluster.') +output fqdn string = aksCluster.outputs.?fqdn ?? '' diff --git a/infra/avm/modules/compute/maintenance-configuration.bicep b/infra/avm/modules/compute/maintenance-configuration.bicep new file mode 100644 index 00000000..2683939d --- /dev/null +++ b/infra/avm/modules/compute/maintenance-configuration.bicep @@ -0,0 +1,84 @@ +// ============================================================================ +// Module: Maintenance Configuration +// Description: AVM wrapper for Azure Maintenance Configuration +// AVM Module: avm/res/maintenance/maintenance-configuration +// WAF: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the maintenance configuration.') +param name string = 'mc-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Maintenance scope.') +param maintenanceScope string = 'InGuestPatch' + +@description('Visibility of the configuration.') +param visibility string = 'Custom' + +@description('Extension properties.') +param extensionProperties object = { + InGuestPatchMode: 'User' +} + +@description('Maintenance window configuration.') +param maintenanceWindow object = { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' +} + +@description('Install patches configuration.') +param installPatches object = { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } +} + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = { + name: take('avm.res.maintenance.maintenance-configuration.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + extensionProperties: extensionProperties + maintenanceScope: maintenanceScope + maintenanceWindow: maintenanceWindow + visibility: visibility + installPatches: installPatches + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the maintenance configuration.') +output resourceId string = maintenanceConfiguration.outputs.resourceId + +@description('Name of the maintenance configuration.') +output name string = maintenanceConfiguration.outputs.name diff --git a/infra/avm/modules/compute/proximity-placement-group.bicep b/infra/avm/modules/compute/proximity-placement-group.bicep new file mode 100644 index 00000000..f1a3e279 --- /dev/null +++ b/infra/avm/modules/compute/proximity-placement-group.bicep @@ -0,0 +1,51 @@ +// ============================================================================ +// Module: Proximity Placement Group +// Description: AVM wrapper for Azure Proximity Placement Group +// AVM Module: avm/res/compute/proximity-placement-group +// WAF: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the proximity placement group.') +param name string = 'ppg-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Availability zone for the proximity placement group.') +param availabilityZone int = 1 + +@description('VM sizes intent for the proximity placement group.') +param vmSizes array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-group:0.4.1' = { + name: take('avm.res.compute.proximity-placement-group.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + availabilityZone: availabilityZone + intent: !empty(vmSizes) ? { vmSizes: vmSizes } : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the proximity placement group.') +output resourceId string = proximityPlacementGroup.outputs.resourceId + +@description('Name of the proximity placement group.') +output name string = proximityPlacementGroup.outputs.name diff --git a/infra/avm/modules/compute/virtual-machine.bicep b/infra/avm/modules/compute/virtual-machine.bicep new file mode 100644 index 00000000..8b9c2a7e --- /dev/null +++ b/infra/avm/modules/compute/virtual-machine.bicep @@ -0,0 +1,157 @@ +// ============================================================================ +// Module: Virtual Machine (Jumpbox) +// Description: AVM wrapper for Azure Virtual Machine with Entra ID authentication +// AVM Module: avm/res/compute/virtual-machine +// Ref: https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the virtual machine.') +param name string = 'vm-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('VM size.') +param vmSize string = 'Standard_D2s_v5' + +@secure() +@description('Local admin username. Required by Azure at provisioning time but not used for login when Entra ID is enabled.') +param adminUsername string + +@secure() +@description('Local admin password. Required by Azure at provisioning time but not used for login when Entra ID is enabled.') +param adminPassword string + +@description('Resource ID of the subnet for the VM NIC.') +param subnetResourceId string + +@description('OS type for the VM.') +param osType string = 'Windows' + +@description('Availability zone for the VM.') +param availabilityZone int = 1 + +@description('Image reference for the VM.') +param imageReference object = { + publisher: 'microsoft-dsvm' + offer: 'dsvm-win-2022' + sku: 'winserver-2022' + version: 'latest' +} + +@description('OS disk size in GB.') +param osDiskSizeGB int = 128 + +@description('Resource ID of the maintenance configuration.') +param maintenanceConfigurationResourceId string? + +@description('Resource ID of the proximity placement group.') +param proximityPlacementGroupResourceId string? + +@description('Monitoring agent extension configuration (data collection rule associations).') +param extensionMonitoringAgentConfig object? + +@description('Diagnostic settings for the resource.') +param diagnosticSettings array? + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('Deploying user principal ID. Used for default role assignment to grant the deploying user login access to the VM. This is required because with Entra ID authentication enabled, local accounts cannot be used to access the VM, including the local admin account created at provisioning.') +param deployingUserPrincipalId string + +@description('Deploying user principal type. Used for default role assignment to grant the deploying user login access to the VM. This is required because with Entra ID authentication enabled, local accounts cannot be used to access the VM, including the local admin account created at provisioning.') +param deployingUserPrincipalType string = 'User' + +@description('Role assignments to apply to the virtual machine.') +param roleAssignments array = [ + { + roleDefinitionIdOrName: '1c0163c0-47e6-4577-8991-ea5c82e286e4' // Virtual Machine Administrator Login + principalId: deployingUserPrincipalId + principalType: deployingUserPrincipalType + } +] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.22.0' = { + name: take('avm.res.compute.virtual-machine.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + computerName: take(name, 15) + osType: osType + vmSize: vmSize + adminUsername: adminUsername + adminPassword: adminPassword + managedIdentities: { systemAssigned: true } + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: maintenanceConfigurationResourceId + enableAutomaticUpdates: true + encryptionAtHost: true + availabilityZone: availabilityZone + proximityPlacementGroupResourceId: proximityPlacementGroupResourceId + imageReference: imageReference + osDisk: { + name: 'osdisk-${name}' + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: osDiskSizeGB + managedDisk: { storageAccountType: 'Premium_LRS' } + } + nicConfigurations: [ + { + name: 'nic-${name}' + tags: tags + deleteOption: 'Delete' + diagnosticSettings: diagnosticSettings + ipConfigurations: [ + { + name: '${name}-nic01-ipconfig01' + subnetResourceId: subnetResourceId + diagnosticSettings: diagnosticSettings + } + ] + } + ] + roleAssignments: roleAssignments + extensionAadJoinConfig: { + enabled: true + tags: tags + typeHandlerVersion: '2.0' + settings: { mdmId: '' } + } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { day: '7', isEnabled: 'true', scanType: 'Quick', time: '120' } + } + tags: tags + } + extensionMonitoringAgentConfig: extensionMonitoringAgentConfig + extensionNetworkWatcherAgentConfig: { enabled: true, tags: tags } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the virtual machine.') +output resourceId string = virtualMachine.outputs.resourceId + +@description('Name of the virtual machine.') +output name string = virtualMachine.outputs.name diff --git a/infra/avm/modules/data/app-configuration.bicep b/infra/avm/modules/data/app-configuration.bicep new file mode 100644 index 00000000..ee3fb318 --- /dev/null +++ b/infra/avm/modules/data/app-configuration.bicep @@ -0,0 +1,98 @@ +// ============================================================================ +// Module: Azure App Configuration (AVM) +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the App Configuration store.') +param name string = 'appcs-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('SKU for the configuration store.') +@allowed(['Free', 'Standard']) +param sku string = 'Standard' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Enable purge protection.') +param enablePurgeProtection bool = false + +@description('Soft delete retention in days.') +param softDeleteRetentionInDays int = 7 + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Role assignments.') +param roleAssignments array = [] + +@description('Key-value pairs to store in the configuration.') +param keyValues array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +// ============================================================================ +// App Configuration (AVM) +// ============================================================================ + +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +module configStore 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { + name: take('avm.res.appconfiguration.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: sku + disableLocalAuth: disableLocalAuth + enablePurgeProtection: enablePurgeProtection + softDeleteRetentionInDays: softDeleteRetentionInDays + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + keyValues: !empty(keyValues) ? keyValues : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the configuration store.') +output name string = configStore.outputs.name + +@description('The endpoint of the configuration store.') +output endpoint string = configStore.outputs.endpoint + +@description('The resource ID of the configuration store.') +output resourceId string = configStore.outputs.resourceId diff --git a/infra/avm/modules/data/cosmos-db-mongo.bicep b/infra/avm/modules/data/cosmos-db-mongo.bicep new file mode 100644 index 00000000..36baef6c --- /dev/null +++ b/infra/avm/modules/data/cosmos-db-mongo.bicep @@ -0,0 +1,137 @@ +// ============================================================================ +// Module: Cosmos DB (MongoDB) +// Description: AVM wrapper for Azure Cosmos DB with MongoDB API +// AVM Module: avm/res/document-db/database-account:0.19.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/cosmos-db +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('MongoDB database name.') +param databaseName string = 'default' + +@description('MongoDB collections to create.') +param collections array = [] + +@description('MongoDB server version.') +@allowed(['4.2', '5.0', '6.0', '7.0']) +param serverVersion string = '7.0' + +@description('Enable analytical storage (Synapse Link).') +param enableAnalyticalStorage bool = false + +@description('Default consistency level.') +@allowed(['Eventual', 'ConsistentPrefix', 'Session', 'BoundedStaleness', 'Strong']) +param consistencyLevel string = 'Session' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for Cosmos DB (MongoDB).') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- WAF: Redundancy --- +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable automatic failover.') +param enableAutomaticFailover bool = false + +@description('Optional. HA paired region for multi-region failover when redundancy is enabled.') +param haLocation string = '' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module cosmosAccount 'br/public:avm/res/document-db/database-account:0.19.0' = { + name: take('avm.res.document-db.database-account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + capabilitiesToAdd: ['EnableMongo'] + serverVersion: serverVersion + enableAnalyticalStorage: enableAnalyticalStorage + defaultConsistencyLevel: consistencyLevel + mongodbDatabases: [ + { + name: databaseName + collections: collections + } + ] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + networkRestrictions: { + networkAclBypass: 'None' + publicNetworkAccess: publicNetworkAccess + } + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'MongoDB' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + zoneRedundant: zoneRedundant + enableAutomaticFailover: enableAutomaticFailover + failoverLocations: zoneRedundant && !empty(haLocation) + ? [ + { failoverPriority: 0, isZoneRedundant: true, locationName: location } + { failoverPriority: 1, isZoneRedundant: true, locationName: haLocation } + ] + : [ + { locationName: location, failoverPriority: 0, isZoneRedundant: false } + ] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmosAccount.outputs.resourceId + +@description('Name of the Cosmos DB account.') +output name string = cosmosAccount.outputs.name + +@description('MongoDB connection string (without credentials — use Key Vault for secrets).') +output connectionString string = 'mongodb+srv://${name}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000' + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.mongo.cosmos.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName diff --git a/infra/avm/modules/data/cosmos-db-nosql.bicep b/infra/avm/modules/data/cosmos-db-nosql.bicep new file mode 100644 index 00000000..49c39f76 --- /dev/null +++ b/infra/avm/modules/data/cosmos-db-nosql.bicep @@ -0,0 +1,146 @@ +// ============================================================================ +// Module: Cosmos DB +// Description: AVM wrapper for Azure Cosmos DB (NoSQL) with WAF alignment +// AVM Module: avm/res/document-db/database-account:0.19.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/cosmos-db +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Database name.') +param databaseName string = 'db_conversation_history' + +@description('Container definitions.') +param containers array = [ + { + name: 'conversations' + partitionKeyPath: '/userId' + } +] + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for Cosmos DB.') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- WAF: Redundancy --- +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable automatic failover.') +param enableAutomaticFailover bool = false + +@description('Optional. HA paired region for multi-region failover when redundancy is enabled.') +param haLocation string = '' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module cosmosAccount 'br/public:avm/res/document-db/database-account:0.19.0' = { + name: take('avm.res.document-db.database-account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + capabilitiesToAdd: zoneRedundant ? [] : ['EnableServerless'] + sqlDatabases: [ + { + name: databaseName + containers: [for container in containers: { + name: container.name + paths: [container.partitionKeyPath] + kind: 'Hash' + version: 2 + }] + } + ] + sqlRoleAssignments: [] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + networkRestrictions: { + networkAclBypass: 'None' + publicNetworkAccess: publicNetworkAccess + } + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'Sql' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + zoneRedundant: zoneRedundant + enableAutomaticFailover: enableAutomaticFailover + failoverLocations: zoneRedundant + ? [ + { + failoverPriority: 0 + isZoneRedundant: true + locationName: location + } + { + failoverPriority: 1 + isZoneRedundant: true + locationName: haLocation + } + ] + : [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmosAccount.outputs.resourceId + +@description('Name of the Cosmos DB account.') +output name string = cosmosAccount.outputs.name + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.documents.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName + +@description('Container name (first container).') +output containerName string = containers[0].name diff --git a/infra/avm/modules/data/event-grid.bicep b/infra/avm/modules/data/event-grid.bicep new file mode 100644 index 00000000..16c67516 --- /dev/null +++ b/infra/avm/modules/data/event-grid.bicep @@ -0,0 +1,65 @@ +// ============================================================================ +// Module: Azure Event Grid System Topic +// Description: AVM wrapper for Azure Event Grid System Topic +// AVM Module: avm/res/event-grid/system-topic:0.6.5 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Event Grid System Topic.') +param name string = 'evgt-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Resource ID of the source that publishes events (e.g., Storage Account resource ID).') +param source string + +@description('The type of the event source. E.g., Microsoft.Storage.StorageAccounts.') +param topicType string + +@description('Event subscriptions to create on the system topic.') +param eventSubscriptions array = [] + +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +@description('Managed identities configuration.') +param managedIdentities object = {} + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module eventGridSystemTopic 'br/public:avm/res/event-grid/system-topic:0.6.5' = { + name: take('avm.res.event-grid.system-topic.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + source: source + topicType: topicType + eventSubscriptions: eventSubscriptions + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + managedIdentities: !empty(managedIdentities) ? managedIdentities : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the Event Grid System Topic.') +output name string = eventGridSystemTopic.outputs.name + +@description('Resource ID of the Event Grid System Topic.') +output resourceId string = eventGridSystemTopic.outputs.resourceId + +@description('System-assigned principal ID (if enabled).') +output systemAssignedMIPrincipalId string = eventGridSystemTopic.outputs.?systemAssignedMIPrincipalId ?? '' diff --git a/infra/avm/modules/data/event-hub.bicep b/infra/avm/modules/data/event-hub.bicep new file mode 100644 index 00000000..3e8efd60 --- /dev/null +++ b/infra/avm/modules/data/event-hub.bicep @@ -0,0 +1,92 @@ +// ============================================================================ +// Module: Azure Event Hub Namespace (AVM) +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Event Hub namespace.') +param name string = 'evhns-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('SKU configuration for the namespace.') +param sku object = { + name: 'Standard' + capacity: 1 +} + +@description('Event hubs to create within the namespace.') +param eventhubs array = [] + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Role assignments.') +param roleAssignments array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +// ============================================================================ +// Event Hub Namespace (AVM) +// ============================================================================ + +var eventHubItems = [for eh in eventhubs: { + name: eh.name + messageRetentionInDays: contains(eh, 'messageRetentionInDays') ? eh.messageRetentionInDays : 1 + partitionCount: contains(eh, 'partitionCount') ? eh.partitionCount : 2 +}] + +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +module eventHubNamespace 'br/public:avm/res/event-hub/namespace:0.14.1' = { + name: take('avm.res.eventhub.namespace.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: sku.name + skuCapacity: sku.capacity + eventhubs: eventHubItems + managedIdentities: !empty(managedIdentities) ? managedIdentities : {} + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the Event Hub namespace.') +output name string = eventHubNamespace.outputs.name + +@description('The resource ID of the Event Hub namespace.') +output resourceId string = eventHubNamespace.outputs.resourceId diff --git a/infra/avm/modules/data/postgresql-flexible-server.bicep b/infra/avm/modules/data/postgresql-flexible-server.bicep new file mode 100644 index 00000000..42cbc4f4 --- /dev/null +++ b/infra/avm/modules/data/postgresql-flexible-server.bicep @@ -0,0 +1,148 @@ +// ============================================================================ +// Module: PostgreSQL Flexible Server +// Description: AVM wrapper for Azure Database for PostgreSQL Flexible Server +// AVM Module: avm/res/db-for-postgre-sql/flexible-server:0.15.4 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/postgresql +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the PostgreSQL Flexible Server.') +param name string = 'psql-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Azure AD administrators for the server. Each entry requires objectId, principalName, and principalType (User, Group, or ServicePrincipal).') +param administrators array + +@description('The PostgreSQL version to deploy.') +param version string = '16' + +@description('SKU name for the PostgreSQL Flexible Server.') +param skuName string = 'Standard_B1ms' + +@description('SKU tier for the PostgreSQL Flexible Server.') +@allowed(['Burstable', 'GeneralPurpose', 'MemoryOptimized']) +param skuTier string = 'Burstable' + +@description('Storage size in GB.') +param storageSizeGB int = 32 + +@description('Availability zone for the server.') +param availabilityZone int = 1 + +@description('Optional databases to create on the server. Each entry should have a name, and optionally charset and collation.') +param databases array = [] + +@description('Optional server configurations (e.g., extensions). Each entry should have a name, value, and source.') +param configurations array = [] + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for PostgreSQL.') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- WAF: Redundancy --- +@description('High availability mode.') +@allowed(['Disabled', 'SameZone', 'ZoneRedundant']) +param highAvailability string = 'Disabled' + +@description('Standby availability zone for high availability.') +param highAvailabilityZone int = -1 + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module postgresServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:0.15.4' = { + name: take('avm.res.postgre-sql.flexible-server.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + tier: skuTier + storageSizeGB: storageSizeGB + version: version + availabilityZone: availabilityZone + highAvailability: highAvailability + highAvailabilityZone: highAvailabilityZone + publicNetworkAccess: publicNetworkAccess + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + administrators: [for admin in administrators: { + objectId: admin.objectId + principalName: admin.principalName + principalType: admin.principalType + }] + firewallRules: publicNetworkAccess == 'Enabled' ? [ + { + name: 'AllowAllAzureServicesAndResourcesWithinAzureIps' + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + { + name: 'AllowAll' + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } + ] : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'postgresqlServer' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + databases: [for db in databases: { + name: db.name + charset: db.?charset ?? 'UTF8' + collation: db.?collation ?? 'en_US.utf8' + }] + configurations: [for config in configurations: { + name: config.name + value: config.value + source: config.source + }] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Fully qualified domain name of the PostgreSQL Flexible Server.') +output serverFqdn string = postgresServer.outputs.?fqdn ?? '${name}.postgres.database.azure.com' + +@description('Name of the PostgreSQL Flexible Server.') +output name string = postgresServer.outputs.name + +@description('Resource ID of the PostgreSQL Flexible Server.') +output resourceId string = postgresServer.outputs.resourceId diff --git a/infra/avm/modules/data/sql-database.bicep b/infra/avm/modules/data/sql-database.bicep new file mode 100644 index 00000000..4afa61b0 --- /dev/null +++ b/infra/avm/modules/data/sql-database.bicep @@ -0,0 +1,140 @@ +// ============================================================================ +// Module: SQL Database +// Description: AVM wrapper for Azure SQL Server and Database +// AVM Module: avm/res/sql/server:0.21.1 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-sql-database +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the SQL Server.') +param name string = 'sql-${solutionName}' + +@description('Name of the SQL Database.') +param databaseName string = 'sqldb-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Principal ID of the deployer for admin access.') +param deployerPrincipalId string + +@description('SKU name for the database.') +param skuName string = 'GP_S_Gen5' + +@description('SKU tier for the database.') +param skuTier string = 'GeneralPurpose' + +@description('SKU family.') +param skuFamily string = 'Gen5' + +@description('vCore capacity.') +param skuCapacity int = 2 + +@description('Auto-pause delay in minutes.') +param autoPauseDelay int = 60 + +@description('Minimum capacity (vCores).') +param minCapacity int = 1 + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for SQL Server.') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module sqlServer 'br/public:avm/res/sql/server:0.21.1' = { + name: take('avm.res.sql.server.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + minimalTlsVersion: '1.2' + publicNetworkAccess: publicNetworkAccess + restrictOutboundNetworkAccess: 'Disabled' + administrators: { + azureADOnlyAuthentication: true + login: deployerPrincipalId + principalType: 'User' + sid: deployerPrincipalId + tenantId: subscription().tenantId + } + databases: [ + { + name: databaseName + availabilityZone: -1 + collation: 'SQL_Latin1_General_CP1_CI_AS' + autoPauseDelay: autoPauseDelay + minCapacity: '${minCapacity}' + zoneRedundant: false + sku: { + name: skuName + tier: skuTier + family: skuFamily + capacity: skuCapacity + } + } + ] + firewallRules: publicNetworkAccess == 'Enabled' ? [ + { + name: 'AllowSpecificRange' + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } + { + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + ] : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'sqlServer' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Fully qualified domain name of the SQL Server.') +output serverFqdn string = '${name}.database.windows.net' + +@description('Name of the SQL Database.') +output databaseName string = databaseName + +@description('Resource ID of the SQL Server.') +output serverResourceId string = sqlServer.outputs.resourceId + +@description('Name of the SQL Server.') +output name string = sqlServer.outputs.name diff --git a/infra/avm/modules/data/storage-account.bicep b/infra/avm/modules/data/storage-account.bicep new file mode 100644 index 00000000..1ff0e497 --- /dev/null +++ b/infra/avm/modules/data/storage-account.bicep @@ -0,0 +1,135 @@ +// ============================================================================ +// Module: Storage Account +// Description: AVM wrapper for Azure Storage Account with WAF alignment +// AVM Module: avm/res/storage/storage-account:0.32.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/storage-accounts +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the storage account.') +param name string = take('st${toLower(replace(solutionName, '-', ''))}', 24) + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Storage account SKU.') +param skuName string = 'Standard_LRS' + +@description('Storage account kind.') +param kind string = 'StorageV2' + +@description('Access tier.') +@allowed(['Hot', 'Cool']) +param accessTier string = 'Hot' + +@description('Allow blob public access.') +param allowBlobPublicAccess bool = false + +@description('Allow shared key access.') +param allowSharedKeyAccess bool = true + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Blob containers to create.') +param containers array = [ + { + name: 'default' + publicAccess: 'None' + } +] + +// --- WAF: Monitoring --- +@description('Diagnostic settings for monitoring.') +param diagnosticSettings array = [] + +// --- WAF: Private Networking --- +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Network ACLs for the storage account.') +param networkAcls object = { + defaultAction: 'Allow' + bypass: 'AzureServices' +} + +@description('Whether to enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for the private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs for Storage (blob).') +param privateDnsZoneResourceIds array = [] + +var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'dns-zone-${i}' + privateDnsZoneResourceId: zoneId +}] + +// --- Role Assignments --- +@description('Optional. Array of role assignments to create on the Storage Account.') +param roleAssignments array = [] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module storage 'br/public:avm/res/storage/storage-account:0.32.0' = { + name: take('avm.res.storage.storage-account.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + kind: kind + accessTier: accessTier + allowBlobPublicAccess: allowBlobPublicAccess + allowSharedKeyAccess: allowSharedKeyAccess + minimumTlsVersion: 'TLS1_2' + supportsHttpsTrafficOnly: true + requireInfrastructureEncryption: true + publicNetworkAccess: publicNetworkAccess + networkAcls: networkAcls + blobServices: { + containers: [for container in containers: { + name: container.name + publicAccess: container.publicAccess + }] + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + } + diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] + privateEndpoints: enablePrivateNetworking ? [ + { + name: 'pep-${name}' + customNetworkInterfaceName: 'nic-${name}' + subnetResourceId: privateEndpointSubnetId + service: 'blob' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: privateDnsZoneConfigs + } + } + ] : [] + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Storage Account.') +output resourceId string = storage.outputs.resourceId + +@description('Name of the Storage Account.') +output name string = storage.outputs.name + +@description('Primary blob endpoint.') +output blobEndpoint string = storage.outputs.primaryBlobEndpoint + +@description('Service endpoints.') +output serviceEndpoints object = storage.outputs.serviceEndpoints diff --git a/infra/avm/modules/fabric/fabric-capacity.bicep b/infra/avm/modules/fabric/fabric-capacity.bicep new file mode 100644 index 00000000..664f60e0 --- /dev/null +++ b/infra/avm/modules/fabric/fabric-capacity.bicep @@ -0,0 +1,72 @@ +// ============================================================================ +// Module: Fabric Capacity +// Description: AVM wrapper for Microsoft Fabric Capacity +// AVM Module: avm/res/fabric/capacity:0.1.2 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.fabric/capacities +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Fabric capacity. Defaults to fc{solutionName}.') +param name string = 'fc${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU tier of the Fabric capacity.') +@allowed([ + 'F2' + 'F4' + 'F8' + 'F16' + 'F32' + 'F64' + 'F128' + 'F256' + 'F512' + 'F1024' + 'F2048' +]) +param skuName string = 'F2' + +@description('List of admin members (UPNs for users, object IDs for service principals).') +param adminMembers array + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Reference +// ============================================================================ + +module fabricCapacity 'br/public:avm/res/fabric/capacity:0.1.2' = { + name: take('avm.res.fabric.capacity.${name}', 64) + params: { + name: name + location: location + skuName: skuName + adminMembers: adminMembers + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the deployed Fabric capacity.') +output name string = fabricCapacity.outputs.name + +@description('The resource ID of the deployed Fabric capacity.') +output resourceId string = fabricCapacity.outputs.resourceId + +@description('The resource group name.') +output resourceGroupName string = fabricCapacity.outputs.resourceGroupName + +@description('The location of the deployed Fabric capacity.') +output location string = fabricCapacity.outputs.location diff --git a/infra/avm/modules/identity/cross-scope-role-assignment.bicep b/infra/avm/modules/identity/cross-scope-role-assignment.bicep new file mode 100644 index 00000000..8ed9e333 --- /dev/null +++ b/infra/avm/modules/identity/cross-scope-role-assignment.bicep @@ -0,0 +1,37 @@ +// ============================================================================ +// cross-scope-role-assignment.bicep +// Description: Reusable helper that creates a single role assignment scoped +// to an existing AI Services resource. Used for cross-resource- +// group RBAC where the AI Services lives in a different RG. +// ============================================================================ + +@description('The principal ID to assign the role to.') +param principalId string + +@description('The resource ID of the role definition to assign.') +param roleDefinitionId string + +@description('A unique name for the role assignment.') +param roleAssignmentName string + +@description('The name of the AI Foundry account to scope the role assignment to.') +param aiFoundryName string + +@description('The principal type of the identity being assigned.') +@allowed(['ServicePrincipal', 'User']) +param principalType string = 'ServicePrincipal' + +// Reference the existing AI Foundry resource in this resource group +resource aiFoundryAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiFoundryName +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: roleAssignmentName + scope: aiFoundryAccount + properties: { + roleDefinitionId: roleDefinitionId + principalId: principalId + principalType: principalType + } +} diff --git a/infra/avm/modules/identity/managed-identity.bicep b/infra/avm/modules/identity/managed-identity.bicep new file mode 100644 index 00000000..f2d264ee --- /dev/null +++ b/infra/avm/modules/identity/managed-identity.bicep @@ -0,0 +1,49 @@ +// ============================================================================ +// Module: Managed Identity +// Description: AVM wrapper for User-Assigned Managed Identity +// AVM Module: avm/res/managed-identity/user-assigned-identity +// Usage: Call this module once per identity from main.bicep +// ============================================================================ + +@description('Solution name used for resource naming.') +param solutionName string + +@description('Name of the managed identity.') +param identityName string = 'id-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module managedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { + name: take('avm.res.managed-identity.user-assigned-identity.${identityName}', 64) + params: { + name: identityName + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the managed identity.') +output resourceId string = managedIdentity.outputs.resourceId + +@description('Principal ID of the managed identity.') +output principalId string = managedIdentity.outputs.principalId + +@description('Client ID of the managed identity.') +output clientId string = managedIdentity.outputs.clientId + +@description('Name of the managed identity.') +output name string = managedIdentity.outputs.name diff --git a/infra/avm/modules/identity/role-assignments.bicep b/infra/avm/modules/identity/role-assignments.bicep new file mode 100644 index 00000000..399e4ae1 --- /dev/null +++ b/infra/avm/modules/identity/role-assignments.bicep @@ -0,0 +1,280 @@ +// ============================================================================ +// Module: Role Assignments (centralized — all cross-service + data plane RBAC) +// Description: RG-level, cross-service, and data-plane role assignments. +// One place to audit "who has access to what". +// ============================================================================ + +// ============================================================================ +// Parameters +// ============================================================================ + +@description('Solution name suffix for generating unique role assignment GUIDs.') +param solutionName string = '' + +@description('Whether to use an existing AI project (true) or create new (false).') +param useExistingAIProject bool = false + +@description('Resource ID of the existing AI project (for deriving AI Services name/sub/RG).') +param existingFoundryProjectResourceId string = '' + +// --- Identity Principal IDs --- + +@description('Principal ID of the AI project identity.') +param aiProjectPrincipalId string = '' + +@description('Principal ID of the existing AI project identity (for cross-service roles).') +param existingAiProjectPrincipalId string = '' + +@description('Principal ID of the AI Search identity.') +param aiSearchPrincipalId string = '' + +@description('Principal ID of the backend App Service system-assigned identity (empty if not deployed).') +param backendAppServicePrincipalId string = '' + +// --- Resource References --- + +@description('Resource ID of the AI Foundry account (empty if not deployed — new project path).') +param aiFoundryResourceId string = '' + +@description('Resource ID of the AI Search service (empty if not deployed).') +param aiSearchResourceId string = '' + +@description('Resource ID of the Storage Account (empty if not deployed).') +param storageAccountResourceId string = '' + +@description('Name of the Cosmos DB account (empty if not deployed).') +param cosmosDbAccountName string = '' + +// ============================================================================ +// Derived Variables +// ============================================================================ + +var existingAIFoundryName = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[8] : '' +var existingAIFoundrySubscription = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[2] : subscription().subscriptionId +var existingAIFoundryResourceGroup = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[4] : resourceGroup().name + +// ============================================================================ +// Role Definitions +// ============================================================================ + +var roleDefinitions = { + azureAiUser: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Foundry User + cognitiveServicesUser: 'a97b65f3-24c7-4388-baec-2e87135dc908' + cognitiveServicesOpenAIUser: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + searchIndexDataReader: '1407120a-92aa-4202-b7e9-c0e197c71c8f' + searchServiceContributor: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' + storageBlobDataContributor: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + storageBlobDataReader: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +} + +// ============================================================================ +// Existing Resource References +// ============================================================================ + +resource aiFoundryAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if (!empty(aiFoundryResourceId)) { + name: last(split(aiFoundryResourceId, '/')) +} + +resource aiSearchService 'Microsoft.Search/searchServices@2025-05-01' existing = if (!empty(aiSearchResourceId)) { + name: last(split(aiSearchResourceId, '/')) +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' existing = if (!empty(storageAccountResourceId)) { + name: last(split(storageAccountResourceId, '/')) +} + +resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + name: cosmosDbAccountName +} + +resource cosmosContributorRoleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + parent: cosmosAccount + name: '00000000-0000-0000-0000-000000000002' // Cosmos DB Built-in Data Contributor +} + +// ============================================================================ +// 1. AI SERVICES ROLE ASSIGNMENTS +// Cross-service roles scoped to AI Foundry account +// ============================================================================ + +// AI Search → Cognitive Services OpenAI User on AI Foundry (new project, same RG) +resource assignOpenAIRoleToAISearch 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiSearchPrincipalId) && !empty(aiFoundryResourceId)) { + name: guid(aiFoundryAccount.id, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + scope: aiFoundryAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Cognitive Services OpenAI User on existing AI Foundry (cross-scope) +module assignOpenAIToSearchExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(aiSearchPrincipalId)) { + name: 'assignOpenAIRoleToAISearchExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + roleAssignmentName: guid(existingAIFoundryName, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + aiFoundryName: existingAIFoundryName + } +} + +// Backend App Service → Foundry User on AI Foundry (new project, same RG) +resource backendAppAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiFoundryResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiFoundryAccount.id, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + scope: aiFoundryAccount + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Foundry User on existing AI Foundry (cross-scope) +module backendAppAiUserExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(backendAppServicePrincipalId)) { + name: 'assignAiUserRoleToBackendExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + roleAssignmentName: guid(existingAIFoundryName, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + aiFoundryName: existingAIFoundryName + } +} + +// ============================================================================ +// 2. SEARCH SERVICE ROLE ASSIGNMENTS +// AI Project and Backend identities → AI Search +// ============================================================================ + +// AI Project → Search Index Data Reader on AI Search (new project) +resource projectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Search Service Contributor on AI Search (new project) +resource projectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Index Data Reader on AI Search +resource existingProjectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Service Contributor on AI Search +resource existingProjectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Search Index Data Reader on AI Search +resource backendAppSearchReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiSearchService.id, backendAppServicePrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 3. STORAGE ROLE ASSIGNMENTS +// AI Project, AI Search, and Existing Project identities → Storage +// ============================================================================ + +// AI Project → Storage Blob Data Contributor (new project) +resource projectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Storage Blob Data Reader (new project) +resource projectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Contributor +resource existingProjectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Reader +resource existingProjectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Storage Blob Data Reader +resource searchStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiSearchPrincipalId)) { + name: guid(storageAccount.id, aiSearchPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 4. COSMOS DB ROLE ASSIGNMENTS +// Backend App Service → Cosmos DB (data-plane, uses sqlRoleAssignments) +// ============================================================================ + +resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) { + parent: cosmosAccount + name: guid(cosmosContributorRoleDefinition.id, cosmosAccount.id, backendAppServicePrincipalId) + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: cosmosContributorRoleDefinition.id + scope: cosmosAccount.id + } +} + diff --git a/infra/avm/modules/monitoring/app-insights.bicep b/infra/avm/modules/monitoring/app-insights.bicep new file mode 100644 index 00000000..b726ae81 --- /dev/null +++ b/infra/avm/modules/monitoring/app-insights.bicep @@ -0,0 +1,76 @@ +// ============================================================================ +// Module: Application Insights +// Description: AVM wrapper for Application Insights with WAF alignment +// AVM Module: avm/res/insights/component:0.7.1 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/application-insights +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}.') +param name string = 'appi-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace to link to.') +param workspaceResourceId string + +@description('Application type.') +param applicationType string = 'web' + +@description('Retention period in days. WAF recommends 365.') +param retentionInDays int = 365 + +@description('Disable IP masking for security. WAF recommends false.') +param disableIpMasking bool = false + +@description('Flow type for Application Insights.') +param flowType string = 'Bluefield' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Kind of Application Insights resource.') +param kind string = 'web' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module appInsights 'br/public:avm/res/insights/component:0.7.1' = { + name: take('avm.res.insights.component.${name}', 64) + params: { + name: name + location: location + tags: tags + workspaceResourceId: workspaceResourceId + kind: kind + applicationType: applicationType + enableTelemetry: enableTelemetry + retentionInDays: retentionInDays + disableIpMasking: disableIpMasking + flowType: flowType + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Application Insights instance.') +output resourceId string = appInsights.outputs.resourceId + +@description('Name of the Application Insights instance.') +output name string = appInsights.outputs.name + +@description('Instrumentation key for the Application Insights instance.') +output instrumentationKey string = appInsights.outputs.instrumentationKey + +@description('Connection string for the Application Insights instance.') +output connectionString string = appInsights.outputs.connectionString + +@description('Application ID of the Application Insights instance.') +output applicationId string = appInsights.outputs.applicationId diff --git a/infra/avm/modules/monitoring/data-collection-rule.bicep b/infra/avm/modules/monitoring/data-collection-rule.bicep new file mode 100644 index 00000000..c1fd7606 --- /dev/null +++ b/infra/avm/modules/monitoring/data-collection-rule.bicep @@ -0,0 +1,149 @@ +// ============================================================================ +// Module: Data Collection Rule +// Description: AVM wrapper for Azure Monitor Data Collection Rule +// AVM Module: avm/res/insights/data-collection-rule +// WAF: Monitoring for VM observability +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the data collection rule. Defaults to dcr-{solutionName}.') +param name string = 'dcr-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace destination.') +param logAnalyticsWorkspaceResourceId string + +@description('Name of the Log Analytics workspace (used for destination naming).') +param logAnalyticsWorkspaceName string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var dcrLogAnalyticsDestinationName = !empty(logAnalyticsWorkspaceName) ? 'la-${logAnalyticsWorkspaceName}-destination' : 'la-${name}-destination' + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:0.11.0' = { + name: take('avm.res.insights.data-collection-rule.${name}', 64) + params: { + name: name + tags: tags + enableTelemetry: enableTelemetry + location: location + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + performanceCounters: [ + { + streams: ['Microsoft-Perf'] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' + } + ] + windowsEventLogs: [ + { + name: 'SecurityAuditEvents' + streams: ['Microsoft-WindowsEvent'] + xPathQueries: [ + 'Security!*[System[(EventID=4624 or EventID=4625)]]' + ] + } + { + name: 'AuditSuccessFailure' + streams: ['Microsoft-Event'] + xPathQueries: [ + 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' + ] + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: dcrLogAnalyticsDestinationName + } + ] + } + dataFlows: [ + { + streams: ['Microsoft-Perf'] + destinations: [dcrLogAnalyticsDestinationName] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + { + streams: ['Microsoft-Event'] + destinations: [dcrLogAnalyticsDestinationName] + transformKql: 'source' + outputStream: 'Microsoft-Event' + } + ] + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the data collection rule.') +output resourceId string = dataCollectionRule.outputs.resourceId + +@description('Name of the data collection rule.') +output name string = dataCollectionRule.outputs.name diff --git a/infra/avm/modules/monitoring/log-analytics.bicep b/infra/avm/modules/monitoring/log-analytics.bicep new file mode 100644 index 00000000..3b231240 --- /dev/null +++ b/infra/avm/modules/monitoring/log-analytics.bicep @@ -0,0 +1,90 @@ +// ============================================================================ +// Module: Log Analytics Workspace +// Description: AVM wrapper for Log Analytics Workspace with WAF alignment +// AVM Module: avm/res/operational-insights/workspace:0.15.0 +// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-log-analytics +// Note: This module only handles NEW workspace creation. +// Existing workspace logic is handled in main.bicep. +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}.') +param name string = 'log-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Retention period in days. WAF recommends 365.') +param retentionInDays int = 365 + +@description('SKU name for the workspace.') +param skuName string = 'PerGB2018' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// --- WAF: Private Networking --- +@description('Public network access for ingestion.') +param publicNetworkAccessForIngestion string = 'Enabled' + +@description('Public network access for query.') +param publicNetworkAccessForQuery string = 'Enabled' + +// --- WAF: Redundancy --- +@description('Enable workspace replication for redundancy.') +param enableReplication bool = false + +@description('Replication location (paired region).') +param replicationLocation string = '' + +@description('Daily quota in GB. WAF recommends 150 GB/day as starting point.') +param dailyQuotaGb string = '' + +// --- WAF: Monitoring (VM data sources for private networking) --- +@description('Data sources for VM monitoring (Windows events, perf counters).') +param dataSources array = [] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module workspace 'br/public:avm/res/operational-insights/workspace:0.15.0' = { + name: take('avm.res.operational-insights.workspace.${name}', 64) + params: { + name: name + location: location + tags: tags + dataRetention: retentionInDays + skuName: skuName + enableTelemetry: enableTelemetry + features: { enableLogAccessUsingOnlyResourcePermissions: true } + diagnosticSettings: [{ useThisWorkspace: true }] + publicNetworkAccessForIngestion: publicNetworkAccessForIngestion + publicNetworkAccessForQuery: publicNetworkAccessForQuery + dailyQuotaGb: !empty(dailyQuotaGb) ? dailyQuotaGb : null + replication: enableReplication ? { + enabled: true + location: replicationLocation + } : null + dataSources: !empty(dataSources) ? dataSources : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Log Analytics workspace.') +output resourceId string = workspace.outputs.resourceId + +@description('Name of the Log Analytics workspace.') +output name string = workspace.outputs.name + +@description('Location of the workspace.') +output location string = location + +@description('Log Analytics workspace customer ID.') +output logAnalyticsWorkspaceId string = workspace.outputs.logAnalyticsWorkspaceId diff --git a/infra/avm/modules/monitoring/portal-dashboard.bicep b/infra/avm/modules/monitoring/portal-dashboard.bicep new file mode 100644 index 00000000..5bf9148d --- /dev/null +++ b/infra/avm/modules/monitoring/portal-dashboard.bicep @@ -0,0 +1,53 @@ +// ============================================================================ +// Module: Portal Dashboard (Application Insights) +// Description: AVM wrapper for Azure Portal Dashboard +// AVM Module: avm/res/portal/dashboard:0.3.2 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the dashboard.') +param name string = 'dash-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Lenses (tile groups) to display on the dashboard.') +param lenses array = [] + +@description('Dashboard metadata (time range, filters, etc.).') +param metadata object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module dashboard 'br/public:avm/res/portal/dashboard:0.3.2' = { + name: take('avm.res.portal.dashboard.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + lenses: lenses + metadata: !empty(metadata) ? metadata : null + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the dashboard.') +output resourceId string = dashboard.outputs.resourceId + +@description('Name of the dashboard.') +output name string = dashboard.outputs.name + +@description('Resource group the dashboard was deployed to.') +output resourceGroupName string = dashboard.outputs.resourceGroupName diff --git a/infra/avm/modules/networking/bastion-host.bicep b/infra/avm/modules/networking/bastion-host.bicep new file mode 100644 index 00000000..bf524087 --- /dev/null +++ b/infra/avm/modules/networking/bastion-host.bicep @@ -0,0 +1,85 @@ +// ============================================================================ +// Module: Bastion Host +// Description: AVM wrapper for Azure Bastion Host +// AVM Module: avm/res/network/bastion-host +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +var name = 'bas-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Resource ID of the virtual network.') +param virtualNetworkResourceId string + +@description('Optional. Diagnostic settings for the resource.') +param diagnosticSettings array? + +@description('SKU name for the Bastion Host.') +param skuName string = 'Standard' + +@description('Number of scale units.') +param scaleUnits int = 4 + +@description('Disable copy/paste functionality.') +param disableCopyPaste bool = true + +@description('Enable file copy functionality.') +param enableFileCopy bool = false + +@description('Enable IP Connect functionality.') +param enableIpConnect bool = false + +@description('Enable shareable link functionality.') +param enableShareableLink bool = false + +@description('Availability zones for the Bastion Host public IP. Pass empty array to disable zone redundancy.') +param availabilityZones array = [] + +@description('Optional. Diagnostic settings for the public IP address.') +param publicIPDiagnosticSettings array? + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = { + name: take('avm.res.network.bastion-host.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + skuName: skuName + virtualNetworkResourceId: virtualNetworkResourceId + availabilityZones: availabilityZones + publicIPAddressObject: { + name: 'pip-${name}' + diagnosticSettings: publicIPDiagnosticSettings + tags: tags + } + disableCopyPaste: disableCopyPaste + enableFileCopy: enableFileCopy + enableIpConnect: enableIpConnect + enableShareableLink: enableShareableLink + scaleUnits: scaleUnits + diagnosticSettings: diagnosticSettings + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Bastion Host.') +output resourceId string = bastionHost.outputs.resourceId + +@description('Name of the Bastion Host.') +output name string = bastionHost.outputs.name diff --git a/infra/avm/modules/networking/private-dns-zone.bicep b/infra/avm/modules/networking/private-dns-zone.bicep new file mode 100644 index 00000000..24bd2892 --- /dev/null +++ b/infra/avm/modules/networking/private-dns-zone.bicep @@ -0,0 +1,40 @@ +// ============================================================================ +// Module: Private DNS Zone +// Description: AVM wrapper for Azure Private DNS Zone +// AVM Module: avm/res/network/private-dns-zone +// Usage: Call once per DNS zone from main.bicep +// ============================================================================ + +@description('Name of the private DNS zone (e.g., privatelink.cognitiveservices.azure.com).') +param name string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Virtual network links to associate with the DNS zone.') +param virtualNetworkLinks array = [] + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module privateDnsZone 'br/public:avm/res/network/private-dns-zone:0.8.1' = { + name: take('avm.res.network.private-dns-zone.${name}', 64) + params: { + name: name + tags: tags + enableTelemetry: enableTelemetry + virtualNetworkLinks: virtualNetworkLinks + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the private DNS zone.') +output resourceId string = privateDnsZone.outputs.resourceId + +@description('Name of the private DNS zone.') +output name string = privateDnsZone.outputs.name diff --git a/infra/avm/modules/networking/private-endpoint.bicep b/infra/avm/modules/networking/private-endpoint.bicep new file mode 100644 index 00000000..04bfff07 --- /dev/null +++ b/infra/avm/modules/networking/private-endpoint.bicep @@ -0,0 +1,52 @@ +// ============================================================================ +// Module: Private Endpoint +// Description: AVM wrapper for Azure Private Endpoint +// AVM Module: avm/res/network/private-endpoint +// Usage: Call once per private endpoint from main.bicep +// ============================================================================ + +@description('Name of the private endpoint.') +param name string + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Custom NIC name for the private endpoint.') +param customNetworkInterfaceName string = '' + +@description('Resource ID of the subnet for the private endpoint.') +param subnetResourceId string + +@description('Private link service connections configuration.') +param privateLinkServiceConnections array + +@description('Optional. Private DNS zone group configuration.') +param privateDnsZoneGroup object? + +// ============================================================================ +// AVM Module Deployment +// ============================================================================ +module privateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = { + name: take('avm.res.network.private-endpoint.${name}', 64) + params: { + name: name + location: location + tags: tags + customNetworkInterfaceName: !empty(customNetworkInterfaceName) ? customNetworkInterfaceName : 'nic-${name}' + subnetResourceId: subnetResourceId + privateLinkServiceConnections: privateLinkServiceConnections + privateDnsZoneGroup: privateDnsZoneGroup + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the private endpoint.') +output resourceId string = privateEndpoint.outputs.resourceId + +@description('Name of the private endpoint.') +output name string = privateEndpoint.outputs.name diff --git a/infra/avm/modules/networking/virtual-network.bicep b/infra/avm/modules/networking/virtual-network.bicep new file mode 100644 index 00000000..241e39d5 --- /dev/null +++ b/infra/avm/modules/networking/virtual-network.bicep @@ -0,0 +1,303 @@ +// ============================================================================ +// Module: Virtual Network +// Description: VNet, Subnets, and NSGs using AVM modules. +// Each subnet gets its own NSG. Subnet config is passed as param. +// AVM Modules: +// - avm/res/network/network-security-group:0.5.3 +// - avm/res/network/virtual-network:0.8.0 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +var name = 'vnet-${solutionName}' + +@description('Azure region for the resource.') +param location string = resourceGroup().location + +@description('Address prefixes for the virtual network.') +param addressPrefixes array + +@description('Subnet configurations.') +param subnets subnetType[] = [ + { + name: 'backend' + addressPrefixes: ['10.0.0.0/27'] + networkSecurityGroup: { + name: 'nsg-backend' + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: ['22', '3389'] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } + } + { + name: 'webserverfarm' + addressPrefixes: ['10.0.4.0/27'] + delegation: 'Microsoft.Web/serverfarms' + privateEndpointNetworkPolicies: 'Enabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroup: { + name: 'nsg-webserverfarm' + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: ['22', '3389'] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } + } + { + name: 'administration' + addressPrefixes: ['10.0.0.32/27'] + networkSecurityGroup: { + name: 'nsg-administration' + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: ['22', '3389'] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } + } + { + name: 'AzureBastionSubnet' + addressPrefixes: ['10.0.0.64/26'] + networkSecurityGroup: { + name: 'nsg-bastion' + securityRules: [ + { + name: 'AllowGatewayManager' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 2702 + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'GatewayManager' + destinationAddressPrefix: '*' + } + } + { + name: 'AllowHttpsInBound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 2703 + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'Internet' + destinationAddressPrefix: '*' + } + } + { + name: 'AllowSshRdpOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 100 + protocol: '*' + sourcePortRange: '*' + destinationPortRanges: ['22', '3389'] + sourceAddressPrefix: '*' + destinationAddressPrefix: 'VirtualNetwork' + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 110 + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: '*' + destinationAddressPrefix: 'AzureCloud' + } + } + ] + } + } +] + +@description('Tags to apply to the resources.') +param tags object = {} + +@description('Resource ID of the Log Analytics Workspace for diagnostics.') +param logAnalyticsWorkspaceId string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Suffix for resource naming.') +param resourceSuffix string + +// ============================================================================ +// NSGs — one per subnet +// ============================================================================ +@batchSize(1) +module nsgs 'br/public:avm/res/network/network-security-group:0.5.3' = [ + for (subnet, i) in subnets: if (!empty(subnet.?networkSecurityGroup)) { + name: take('avm.res.network.nsg.${subnet.?networkSecurityGroup.name}.${resourceSuffix}', 64) + params: { + name: '${subnet.?networkSecurityGroup.name}-${resourceSuffix}' + location: location + securityRules: subnet.?networkSecurityGroup.securityRules + tags: tags + enableTelemetry: enableTelemetry + } + } +] + +// ============================================================================ +// Virtual Network + Subnets +// ============================================================================ +module virtualNetwork 'br/public:avm/res/network/virtual-network:0.8.0' = { + name: take('avm.res.network.virtual-network.${name}', 64) + params: { + name: name + location: location + addressPrefixes: addressPrefixes + subnets: [ + for (subnet, i) in subnets: { + name: subnet.name + addressPrefixes: subnet.?addressPrefixes + networkSecurityGroupResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null + privateEndpointNetworkPolicies: subnet.?privateEndpointNetworkPolicies + privateLinkServiceNetworkPolicies: subnet.?privateLinkServiceNetworkPolicies + delegation: subnet.?delegation + } + ] + diagnosticSettings: [ + { + name: 'vnetDiagnostics' + workspaceResourceId: logAnalyticsWorkspaceId + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + metricCategories: [ + { + category: 'AllMetrics' + enabled: true + } + ] + } + ] + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +output name string = virtualNetwork.outputs.name +output resourceId string = virtualNetwork.outputs.resourceId + +output subnets subnetOutputType[] = [ + for (subnet, i) in subnets: { + name: subnet.name + resourceId: virtualNetwork.outputs.subnetResourceIds[i] + nsgName: !empty(subnet.?networkSecurityGroup) ? subnet.?networkSecurityGroup.name : null + nsgResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null + } +] + +// Individual subnet outputs for backward compatibility +output backendSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'backend') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'backend')] + : '' +output webserverfarmSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'webserverfarm') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'webserverfarm')] + : '' +output administrationSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'administration') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'administration')] + : '' +output bastionSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'AzureBastionSubnet') + ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'AzureBastionSubnet')] + : '' + +// ============================================================================ +// Custom Types +// ============================================================================ +@export() +@description('Subnet output type') +type subnetOutputType = { + @description('The name of the subnet.') + name: string + @description('The resource ID of the subnet.') + resourceId: string + @description('The name of the associated NSG, if any.') + nsgName: string? + @description('The resource ID of the associated NSG, if any.') + nsgResourceId: string? +} + +@export() +@description('Subnet configuration type') +type subnetType = { + @description('Required. The name of the subnet.') + name: string + @description('Required. Address prefixes for the subnet.') + addressPrefixes: string[] + @description('Optional. Delegation for the subnet.') + delegation: string? + @description('Optional. Private endpoint network policies.') + privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? + @description('Optional. Private link service network policies.') + privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? + @description('Optional. NSG configuration for the subnet.') + networkSecurityGroup: networkSecurityGroupType? + @description('Optional. Route table resource ID.') + routeTableResourceId: string? + @description('Optional. Service endpoint policies.') + serviceEndpointPolicies: object[]? + @description('Optional. Service endpoints to enable.') + serviceEndpoints: string[]? + @description('Optional. Disable default outbound connectivity.') + defaultOutboundAccess: bool? +} + +@export() +@description('NSG configuration type') +type networkSecurityGroupType = { + @description('Required. The name of the NSG.') + name: string + @description('Required. Security rules for the NSG.') + securityRules: object[] +} diff --git a/infra/avm/modules/security/key-vault.bicep b/infra/avm/modules/security/key-vault.bicep new file mode 100644 index 00000000..924eea5b --- /dev/null +++ b/infra/avm/modules/security/key-vault.bicep @@ -0,0 +1,109 @@ +// ============================================================================ +// Module: Azure Key Vault (AVM) +// AVM Module: avm/res/key-vault/vault:0.12.1 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Optional. Override name for the Key Vault. Defaults to kv-{solutionName}.') +param name string = take('kv-${solutionName}', 24) + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the key vault.') +@allowed(['standard', 'premium']) +param sku string = 'standard' + +@description('Enable RBAC authorization.') +param enableRbacAuthorization bool = true + +@description('Enable soft delete.') +param enableSoftDelete bool = true + +@description('Soft delete retention in days.') +param softDeleteRetentionInDays int = 90 + +@description('Enable purge protection.') +param enablePurgeProtection bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Secrets to store in the vault (name/value pairs).') +param secrets array = [] + +@description('Enable Azure telemetry collection.') +param enableTelemetry bool = true + +@description('Role assignments.') +param roleAssignments array = [] + +@description('Enable private networking.') +param enablePrivateNetworking bool = false + +@description('Subnet resource ID for private endpoint.') +param privateEndpointSubnetId string = '' + +@description('Private DNS zone resource IDs.') +param privateDnsZoneResourceIds array = [] + +// ============================================================================ +// Key Vault (AVM) +// ============================================================================ + +var secretItems = [for secret in secrets: { + name: secret.name + value: secret.value +}] + +var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { + name: 'config${i}' + privateDnsZoneResourceId: zoneId +}] + +var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ + { + subnetResourceId: privateEndpointSubnetId + privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { + privateDnsZoneGroupConfigs: dnsZoneConfigs + } : null + } +] : [] + +module keyVault 'br/public:avm/res/key-vault/vault:0.12.1' = { + name: take('avm.res.keyvault.vault.${name}', 64) + params: { + name: name + location: location + tags: tags + enableTelemetry: enableTelemetry + sku: sku + enableRbacAuthorization: enableRbacAuthorization + enableSoftDelete: enableSoftDelete + softDeleteRetentionInDays: softDeleteRetentionInDays + enablePurgeProtection: enablePurgeProtection + publicNetworkAccess: publicNetworkAccess + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + secrets: !empty(secrets) ? secretItems : [] + privateEndpoints: privateEndpointConfig + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the key vault.') +output name string = keyVault.outputs.name + +@description('The URI of the key vault.') +output uri string = keyVault.outputs.uri + +@description('The resource ID of the key vault.') +output resourceId string = keyVault.outputs.resourceId diff --git a/infra/bicep/modules/ai/ai-foundry-connection.bicep b/infra/bicep/modules/ai/ai-foundry-connection.bicep new file mode 100644 index 00000000..b0af1f6d --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry-connection.bicep @@ -0,0 +1,84 @@ +// ============================================================================ +// Module: AI Foundry Project Connection (Single) — Vanilla Bicep +// Description: Creates a single connection on an AI Foundry project. +// Generic, reusable — call once per connection type from main.bicep. +// Supports any connection category (CognitiveSearch, AzureBlob, +// AppInsights, RemoteTool, etc.) via parameterized properties. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name of the AI Foundry project.') +param projectName string + +@description('Required. Solution name suffix used to generate the connection name.') +param solutionName string + +@description('Optional. Connection name. Defaults to lowercase category with solution suffix.') +param connectionName string = toLower('${category}-connection-${solutionName}') + +@description('Required. Connection category (e.g., CognitiveSearch, AzureBlob, AppInsights, RemoteTool).') +param category string + +@description('Required. Connection target (URL or resource ID).') +param target string + +@description('Required. Authentication type (e.g., AAD, ApiKey, ProjectManagedIdentity).') +param authType string + +@description('Optional. Whether the connection is shared to all project users.') +param isSharedToAll bool = true + +@description('Optional. Whether this is the default connection for its category.') +param isDefault bool = false + +@description('Optional. Connection metadata object.') +param metadata object = {} + +@secure() +@description('Optional. Credentials key (for ApiKey auth type).') +param credentialsKey string = '' + +// ============================================================================ +// Existing Resource References +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: aiServicesAccount + name: projectName +} + +// ============================================================================ +// Connection +// ============================================================================ +var baseProperties = { + category: category + target: target + authType: authType + isSharedToAll: isSharedToAll + metadata: metadata +} + +var optionalDefault = isDefault ? { isDefault: true } : {} +var optionalCredentials = !empty(credentialsKey) ? { credentials: { key: credentialsKey } } : {} + +resource connection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-12-01' = { + parent: aiProject + name: connectionName + properties: any(union(baseProperties, optionalDefault, optionalCredentials)) +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Connection name.') +output connectionName string = connection.name + +@description('Connection resource ID.') +output connectionId string = connection.id diff --git a/infra/bicep/modules/ai/ai-foundry-model-deployment.bicep b/infra/bicep/modules/ai/ai-foundry-model-deployment.bicep new file mode 100644 index 00000000..4ed69a72 --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry-model-deployment.bicep @@ -0,0 +1,66 @@ +// ============================================================================ +// Module: Model Deployment — Vanilla Bicep +// Description: Deploys a single AI model to an existing AI Services account. +// Called repetitively from main.bicep for each model in the array. +// Generic, reusable across GSAs. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Name of the parent AI Services account.') +param aiServicesAccountName string + +@description('Required. Name for this model deployment.') +param deploymentName string + +@description('Optional. Model format (e.g., OpenAI).') +param modelFormat string = 'OpenAI' + +@description('Required. Model name (e.g., gpt-4o, text-embedding-ada-002).') +param modelName string + +@description('Optional. Model version. Empty string means latest.') +param modelVersion string = '' + +@description('Optional. RAI policy name.') +param raiPolicyName string = 'Microsoft.Default' + +@description('Required. SKU name (e.g., Standard, GlobalStandard).') +param skuName string + +@description('Required. SKU capacity (tokens per minute in thousands).') +param skuCapacity int + +// ============================================================================ +// Model Deployment +// ============================================================================ +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesAccountName +} + +resource modelDeployment 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { + parent: aiServicesAccount + name: deploymentName + properties: { + model: { + format: modelFormat + name: modelName + version: !empty(modelVersion) ? modelVersion : null + } + raiPolicyName: raiPolicyName + } + sku: { + name: skuName + capacity: skuCapacity + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Name of the deployed model.') +output name string = modelDeployment.name + +@description('Resource ID of the model deployment.') +output resourceId string = modelDeployment.id diff --git a/infra/bicep/modules/ai/ai-foundry-project.bicep b/infra/bicep/modules/ai/ai-foundry-project.bicep new file mode 100644 index 00000000..9d0dd61f --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry-project.bicep @@ -0,0 +1,111 @@ +// ============================================================================ +// Module: AI Foundry Project (Account + Project) — Vanilla Bicep +// Description: Creates an Azure AI Services account and AI Foundry project. +// Generic, reusable across GSAs — no app-specific parameters. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Required. Solution name suffix used to generate resource names.') +param solutionName string + +@description('Optional. Override name for the AI Services account. Defaults to aif-{solutionName}.') +param name string = 'aif-${solutionName}' + +@description('Optional. Override name for the AI Foundry project. Defaults to proj-{solutionName}.') +param projectName string = 'proj-${solutionName}' + +@description('Required. Azure region for the resources.') +param location string + +@description('Optional. Tags to apply to resources.') +param tags object = {} + +@description('Optional. SKU name for the AI Services account.') +param skuName string = 'S0' + +@description('Optional. Whether to disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Optional. Whether to allow project management (AI Foundry hub).') +param allowProjectManagement bool = true + +@description('Optional. Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Managed identity type for the resources.') +@allowed(['SystemAssigned', 'UserAssigned', 'SystemAssigned, UserAssigned', 'None']) +param identityType string = 'SystemAssigned' + +@description('Optional. Network ACLs default action.') +@allowed(['Allow', 'Deny']) +param networkAclsDefaultAction string = 'Allow' + +// ============================================================================ +// AI Services Account +// ============================================================================ +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + } + kind: 'AIServices' + identity: { + type: identityType + } + properties: { + allowProjectManagement: allowProjectManagement + customSubDomainName: name + networkAcls: { + defaultAction: networkAclsDefaultAction + virtualNetworkRules: [] + ipRules: [] + } + publicNetworkAccess: publicNetworkAccess + disableLocalAuth: disableLocalAuth + } +} + +// ============================================================================ +// AI Foundry Project +// ============================================================================ +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { + parent: aiServices + name: projectName + location: location + kind: 'AIServices' + identity: { + type: identityType + } + properties: {} +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the AI Services account.') +output resourceId string = aiServices.id + +@description('Name of the AI Services account.') +output name string = aiServices.name + +@description('Endpoint of the AI Services account (OpenAI Language Model Instance API).') +output endpoint string = aiServices.properties.endpoints['OpenAI Language Model Instance API'] + +@description('System-assigned identity principal ID of the AI Services account.') +output principalId string = aiServices.identity.principalId + +@description('Resource ID of the AI Foundry project.') +output projectResourceId string = aiProject.id + +@description('Name of the AI Foundry project.') +output projectName string = aiProject.name + +@description('AI Foundry project endpoint.') +output projectEndpoint string = aiProject.properties.endpoints['AI Foundry API'] + +@description('System-assigned identity principal ID of the project.') +output projectIdentityPrincipalId string = aiProject.identity.principalId diff --git a/infra/bicep/modules/ai/ai-foundry.bicep b/infra/bicep/modules/ai/ai-foundry.bicep new file mode 100644 index 00000000..35cbb0f2 --- /dev/null +++ b/infra/bicep/modules/ai/ai-foundry.bicep @@ -0,0 +1,74 @@ +// ============================================================================ +// Module: Azure AI Foundry (Cognitive Services Account) +// Description: Deploys an Azure AI Services account with AI Foundry capabilities. +// ============================================================================ + +@description('Required. Name of the AI Services account.') +param name string + +@description('Required. Azure region for the resource.') +param location string + +@description('Optional. Principal IDs to assign Cognitive Services OpenAI User role.') +param principalIds array = [] + +@description('Optional. Whether public network access is allowed.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Tags to apply to the resource.') +param tags object = {} + +resource aiServices 'Microsoft.CognitiveServices/accounts@2024-10-01' = { + name: name + location: location + tags: tags + kind: 'AIServices' + identity: { + type: 'SystemAssigned' + } + sku: { + name: 'S0' + } + properties: { + customSubDomainName: name + publicNetworkAccess: publicNetworkAccess + disableLocalAuth: true + allowProjectManagement: true + networkAcls: { + bypass: 'AzureServices' + defaultAction: publicNetworkAccess == 'Enabled' ? 'Allow' : 'Deny' + } + } +} + +// Assign Cognitive Services OpenAI User role to provided principal IDs +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for principalId in principalIds: { + name: guid(aiServices.id, principalId, 'Cognitive Services OpenAI User') + scope: aiServices + properties: { + principalId: principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a97b65f3-24c7-4388-baec-2e87135dc908' // Cognitive Services OpenAI User + ) + principalType: 'ServicePrincipal' + } + } +] + +@description('The name of the deployed AI Services account.') +output name string = aiServices.name + +@description('The resource ID of the AI Services account.') +output resourceId string = aiServices.id + +@description('The endpoint of the AI Services account.') +output endpoint string = aiServices.properties.endpoint + +@description('The principal ID of the system-assigned managed identity.') +output systemAssignedPrincipalId string = aiServices.identity.principalId diff --git a/infra/bicep/modules/ai/ai-search-identity.bicep b/infra/bicep/modules/ai/ai-search-identity.bicep new file mode 100644 index 00000000..da2309b8 --- /dev/null +++ b/infra/bicep/modules/ai/ai-search-identity.bicep @@ -0,0 +1,65 @@ +// ============================================================================ +// Module: AI Search Identity Update +// Description: Separate deployment that enables managed identity and applies +// full configuration on an existing AI Search service. +// Called by ai-search.bicep as Step 2 of the two-step pattern. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('The name of the existing AI Search service.') +param name string + +@description('The Azure region of the search service.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the search service.') +param skuName string = 'basic' + +@description('Number of replicas.') +param replicaCount int = 1 + +@description('Number of partitions.') +param partitionCount int = 1 + +@description('Hosting mode.') +@allowed(['Default', 'HighDensity']) +param hostingMode string = 'Default' + +@description('Semantic search tier.') +param semanticSearch string = 'free' + +@description('Whether to disable local authentication.') +param disableLocalAuth bool = true + +@description('Managed identity type for the search service.') +param managedIdentityType string = 'SystemAssigned' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +resource searchServiceUpdate 'Microsoft.Search/searchServices@2025-05-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + } + identity: { + type: managedIdentityType + } + properties: { + replicaCount: replicaCount + partitionCount: partitionCount + hostingMode: hostingMode + semanticSearch: semanticSearch + disableLocalAuth: disableLocalAuth + publicNetworkAccess: publicNetworkAccess + } +} + +@description('The principal ID of the AI Search system-assigned managed identity.') +output systemAssignedMIPrincipalId string = searchServiceUpdate.identity.principalId diff --git a/infra/bicep/modules/ai/ai-search.bicep b/infra/bicep/modules/ai/ai-search.bicep new file mode 100644 index 00000000..06c31880 --- /dev/null +++ b/infra/bicep/modules/ai/ai-search.bicep @@ -0,0 +1,97 @@ +// ============================================================================ +// Module: AI Search +// Description: Deploys Azure AI Search with a two-step pattern: +// Step 1: Plain Bicep resource for fast initial creation (name, location, SKU) +// Step 2: Separate module deployment to enable managed identity & full config +// This reduces deployment time by making the resource available immediately +// while identity enablement proceeds as a separate ARM deployment. +// ============================================================================ + +targetScope = 'resourceGroup' + +@description('Solution name suffix used to derive the resource name.') +@minLength(3) +param solutionName string + +@description('Optional. Override name for the search service. Defaults to srch-{solutionName}.') +param name string = 'srch-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the search service.') +@allowed(['free', 'basic', 'standard', 'standard2', 'standard3', 'storage_optimized_l1', 'storage_optimized_l2']) +param skuName string = 'basic' + +@description('Number of replicas.') +param replicaCount int = 1 + +@description('Number of partitions.') +param partitionCount int = 1 + +@description('Hosting mode.') +@allowed(['Default', 'HighDensity']) +param hostingMode string = 'Default' + +@description('Semantic search tier.') +@allowed(['disabled', 'free', 'standard']) +param semanticSearch string = 'free' + +@description('Whether to disable local authentication.') +param disableLocalAuth bool = true + +@description('Managed identity type for the search service.') +param managedIdentityType string = 'SystemAssigned' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// Step 1: Initial resource creation (fast — no identity) +// ============================================================================ +resource aiSearch 'Microsoft.Search/searchServices@2025-05-01' = { + name: name + location: location + sku: { + name: skuName + } +} + +// ============================================================================ +// Step 2: Separate deployment — enables identity & full configuration +// ============================================================================ +module searchServiceUpdate 'ai-search-identity.bicep' = { + name: 'searchServiceUpdate' + params: { + name: aiSearch.name + location: location + tags: tags + skuName: skuName + replicaCount: replicaCount + partitionCount: partitionCount + hostingMode: hostingMode + semanticSearch: semanticSearch + disableLocalAuth: disableLocalAuth + managedIdentityType: managedIdentityType + publicNetworkAccess: publicNetworkAccess + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the AI Search service.') +output resourceId string = aiSearch.id + +@description('Name of the AI Search service.') +output name string = aiSearch.name + +@description('Endpoint URL of the AI Search service.') +output endpoint string = 'https://${aiSearch.name}.search.windows.net' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = searchServiceUpdate.outputs.systemAssignedMIPrincipalId diff --git a/infra/bicep/modules/ai/ai-services.bicep b/infra/bicep/modules/ai/ai-services.bicep new file mode 100644 index 00000000..4c3d6128 --- /dev/null +++ b/infra/bicep/modules/ai/ai-services.bicep @@ -0,0 +1,87 @@ +// ============================================================================ +// Module: Azure AI Services (Generic) +// Description: Deploys Cognitive Services — supports Content Safety, +// Speech, Computer Vision, Document Intelligence, and others. +// API: Microsoft.CognitiveServices/accounts@2025-04-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name prefix for the resource (e.g., cs, speech, cv, docintel).') +param namePrefix string + +@description('The kind of Cognitive Service to deploy.') +@allowed([ + 'ContentSafety' + 'SpeechServices' + 'ComputerVision' + 'FormRecognizer' + 'TextAnalytics' + 'TextTranslation' + 'Face' + 'OpenAI' + 'AIServices' +]) +param kind string + +@description('Optional. Override name for the resource. Defaults to {namePrefix}-{solutionName}.') +param name string = '${namePrefix}-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU for the Cognitive Services account.') +@allowed(['F0', 'S0', 'S1']) +param sku string = 'S0' + +@description('Custom subdomain name for the account.') +param customSubDomainName string = '' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +var effectiveSubDomain = !empty(customSubDomainName) ? customSubDomainName : name + +// ============================================================================ +// Resource +// ============================================================================ +resource aiService 'Microsoft.CognitiveServices/accounts@2025-12-01' = { + name: name + location: location + tags: tags + kind: kind + sku: { + name: sku + } + identity: { + type: 'SystemAssigned' + } + properties: { + customSubDomainName: effectiveSubDomain + publicNetworkAccess: publicNetworkAccess + disableLocalAuth: disableLocalAuth + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AI Services account.') +output name string = aiService.name + +@description('Resource ID of the AI Services account.') +output resourceId string = aiService.id + +@description('Endpoint of the AI Services account.') +output endpoint string = aiService.properties.endpoint + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = aiService.identity.principalId diff --git a/infra/bicep/modules/ai/existing-project-setup.bicep b/infra/bicep/modules/ai/existing-project-setup.bicep new file mode 100644 index 00000000..37cd666d --- /dev/null +++ b/infra/bicep/modules/ai/existing-project-setup.bicep @@ -0,0 +1,51 @@ +// ============================================================================ +// Module: Existing AI Foundry Project Reference — Vanilla Bicep +// Description: References an existing AI Services account and project to +// retrieve their identities. No deployments, no connections. +// Use generic ai-foundry-connection and ai-foundry-model-deployment +// modules for those concerns. +// ============================================================================ + +@description('Required. The name of the existing Cognitive Services account.') +param name string + +@description('Required. The name of the existing AI project.') +param projectName string + +// ============================================================================ +// Existing Resource References +// ============================================================================ + +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: name +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { + parent: aiServices + name: projectName +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The principal ID of the AI Foundry system-assigned managed identity.') +output aiFoundryPrincipalId string = contains(aiServices, 'identity') && contains(aiServices.identity, 'principalId') ? aiServices.identity.principalId : '' + +@description('The principal ID of the AI Project system-assigned managed identity.') +output aiProjectPrincipalId string = contains(aiProject, 'identity') && contains(aiProject.identity, 'principalId') ? aiProject.identity.principalId : '' + +@description('The name of the AI Services account.') +output aiServicesAccountName string = aiServices.name + +@description('The name of the AI project.') +output aiProjectName string = aiProject.name + +@description('The endpoint URL for the Azure OpenAI service.') +output aiFoundryEndpoint string = 'https://${name}.openai.azure.com/' + +@description('The endpoint URL for the AI Foundry project.') +output projectEndpoint string = 'https://${name}.services.ai.azure.com/api/projects/${projectName}' + +@description('The resource ID of the AI Services account.') +output aiFoundryResourceId string = aiServices.id diff --git a/infra/bicep/modules/compute/app-service-plan.bicep b/infra/bicep/modules/compute/app-service-plan.bicep new file mode 100644 index 00000000..f9409f0c --- /dev/null +++ b/infra/bicep/modules/compute/app-service-plan.bicep @@ -0,0 +1,60 @@ +// ============================================================================ +// Module: App Service Plan +// Description: Creates an Azure App Service Plan +// API: Microsoft.Web/serverfarms@2025-05-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service Plan.') +param name string = 'asp-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU name for the App Service Plan.') +@allowed(['F1', 'D1', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1', 'P2', 'P3', 'P4', 'P0v3', 'P0v4', 'P1v3', 'P1v4', 'P2v3', 'P3v3']) +param skuName string = 'B2' + +@description('Whether the plan is Linux-based.') +param reserved bool = true + +@description('Kind of the App Service Plan.') +param kind string = 'linux' + +@description('Number of instances (workers).') +param skuCapacity int = 1 + +@description('Enable zone redundancy. Requires Premium SKU (P1v3+).') +param zoneRedundant bool = false + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource appServicePlan 'Microsoft.Web/serverfarms@2025-05-01' = { + name: name + location: location + tags: tags + kind: kind + sku: { + name: skuName + capacity: skuCapacity + } + properties: { + reserved: reserved + zoneRedundant: zoneRedundant + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service Plan.') +output resourceId string = appServicePlan.id + +@description('Name of the App Service Plan.') +output name string = appServicePlan.name diff --git a/infra/bicep/modules/compute/app-service.bicep b/infra/bicep/modules/compute/app-service.bicep new file mode 100644 index 00000000..0142878e --- /dev/null +++ b/infra/bicep/modules/compute/app-service.bicep @@ -0,0 +1,111 @@ +// ============================================================================ +// Module: App Service +// Description: Creates an Azure App Service (Web App) +// API: Microsoft.Web/sites@2025-05-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the App Service.') +param name string = solutionName + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Docker image name (e.g., DOCKER|registry.azurecr.io/image:tag).') +param linuxFxVersion string + +@description('Application settings key-value pairs.') +param appSettings object = {} + +@description('Whether to enable Always On.') +param alwaysOn bool = true + +@description('Kind of web app.') +param kind string = 'app,linux' + +@description('Subnet resource ID for VNet integration.') +param virtualNetworkSubnetId string = '' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource appService 'Microsoft.Web/sites@2025-05-01' = { + name: name + location: location + tags: tags + kind: kind + identity: { + type: 'SystemAssigned' + } + properties: { + serverFarmId: serverFarmResourceId + publicNetworkAccess: publicNetworkAccess + virtualNetworkSubnetId: !empty(virtualNetworkSubnetId) ? virtualNetworkSubnetId : null + siteConfig: { + alwaysOn: alwaysOn + ftpsState: 'Disabled' + linuxFxVersion: linuxFxVersion + } + endToEndEncryptionEnabled: true + } + + resource basicPublishingCredentialsPoliciesFtp 'basicPublishingCredentialsPolicies' = { + name: 'ftp' + properties: { + allow: false + } + } + resource basicPublishingCredentialsPoliciesScm 'basicPublishingCredentialsPolicies' = { + name: 'scm' + properties: { + allow: false + } + } +} + +resource configAppSettings 'Microsoft.Web/sites/config@2025-05-01' = { + name: 'appsettings' + parent: appService + properties: appSettings +} + +resource configLogs 'Microsoft.Web/sites/config@2025-05-01' = { + name: 'logs' + parent: appService + properties: { + applicationLogs: { fileSystem: { level: 'Verbose' } } + detailedErrorMessages: { enabled: true } + failedRequestsTracing: { enabled: true } + httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } } + } + dependsOn: [configAppSettings] +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the App Service.') +output resourceId string = appService.id + +@description('Name of the App Service.') +output name string = appService.name + +@description('Default hostname of the App Service.') +output defaultHostname string = appService.properties.defaultHostName + +@description('URL of the App Service.') +output appUrl string = 'https://${appService.properties.defaultHostName}' + +@description('System-assigned identity principal ID.') +output identityPrincipalId string = appService.identity.principalId diff --git a/infra/bicep/modules/compute/container-app-environment.bicep b/infra/bicep/modules/compute/container-app-environment.bicep new file mode 100644 index 00000000..c565a158 --- /dev/null +++ b/infra/bicep/modules/compute/container-app-environment.bicep @@ -0,0 +1,63 @@ +// ============================================================================ +// Module: Azure Container Apps Environment +// Description: Creates an Azure Container Apps managed environment +// API: Microsoft.App/managedEnvironments@2024-03-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Container Apps Environment.') +param name string = 'cae-${solutionName}' + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace.') +param logAnalyticsWorkspaceResourceId string + +@description('Subnet resource ID for VNet integration (optional).') +param infrastructureSubnetId string = '' + +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2024-03-01' = { + name: name + location: location + tags: tags + properties: { + appLogsConfiguration: { + destination: 'log-analytics' + logAnalyticsConfiguration: { + customerId: reference(logAnalyticsWorkspaceResourceId, '2023-09-01').customerId + sharedKey: listKeys(logAnalyticsWorkspaceResourceId, '2023-09-01').primarySharedKey + } + } + vnetConfiguration: empty(infrastructureSubnetId) ? null : { + infrastructureSubnetId: infrastructureSubnetId + } + zoneRedundant: zoneRedundant + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the Container Apps Environment.') +output name string = containerAppEnvironment.name + +@description('The resource ID of the Container Apps Environment.') +output resourceId string = containerAppEnvironment.id + +@description('The default domain of the Container Apps Environment.') +output defaultDomain string = containerAppEnvironment.properties.defaultDomain + +@description('The static IP address of the Container Apps Environment.') +output staticIp string = containerAppEnvironment.properties.staticIp diff --git a/infra/bicep/modules/compute/container-app.bicep b/infra/bicep/modules/compute/container-app.bicep new file mode 100644 index 00000000..15596c7d --- /dev/null +++ b/infra/bicep/modules/compute/container-app.bicep @@ -0,0 +1,117 @@ +// ============================================================================ +// Module: Azure Container App +// Description: Creates an Azure Container App +// API: Microsoft.App/containerApps@2024-10-02-preview +// ============================================================================ + +@description('Name of the container app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the Container Apps Environment.') +param environmentResourceId string + +@description('Container definitions.') +param containers array + +@description('Enable external ingress.') +param ingressExternal bool = true + +@description('Target port for ingress.') +param ingressTargetPort int = 80 + +@description('Ingress transport protocol.') +@allowed(['auto', 'http', 'http2', 'tcp']) +param ingressTransport string = 'auto' + +@description('Whether to allow insecure ingress connections.') +param ingressAllowInsecure bool = false + +@description('Disable ingress entirely (for background workers).') +param disableIngress bool = false + +@description('Container registry configurations.') +param registries array? + +@description('Secret definitions.') +param secrets array? + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('CORS policy configuration.') +param corsPolicy object = {} + +@description('Active revision mode.') +@allowed(['Single', 'Multiple']) +param activeRevisionsMode string = 'Single' + +@description('Scale settings (maxReplicas, minReplicas, rules).') +param scaleSettings object = { + maxReplicas: 10 + minReplicas: 0 +} + +@description('Workload profile name.') +param workloadProfileName string? + +// ============================================================================ +// Resource Deployment +// ============================================================================ +var identityConfig = empty(managedIdentities) ? { type: 'None' } : { + type: contains(managedIdentities, 'userAssignedResourceIds') ? (contains(managedIdentities, 'systemAssigned') && managedIdentities.systemAssigned ? 'SystemAssigned,UserAssigned' : 'UserAssigned') : 'SystemAssigned' + userAssignedIdentities: contains(managedIdentities, 'userAssignedResourceIds') ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, id) => union(cur, { '${id}': {} })) : null +} + +var ingressConfig = disableIngress ? null : { + external: ingressExternal + targetPort: ingressTargetPort + transport: ingressTransport + allowInsecure: ingressAllowInsecure + corsPolicy: !empty(corsPolicy) ? corsPolicy : null +} + +resource containerApp 'Microsoft.App/containerApps@2024-10-02-preview' = { + name: name + location: location + tags: tags + identity: identityConfig + properties: { + managedEnvironmentId: environmentResourceId + workloadProfileName: workloadProfileName + configuration: { + activeRevisionsMode: activeRevisionsMode + ingress: ingressConfig + registries: registries + secrets: secrets + } + template: { + containers: containers + scale: { + minReplicas: scaleSettings.minReplicas + maxReplicas: scaleSettings.maxReplicas + rules: contains(scaleSettings, 'rules') ? scaleSettings.rules : null + } + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container app.') +output name string = containerApp.name + +@description('The resource ID of the container app.') +output resourceId string = containerApp.id + +@description('The FQDN of the container app.') +output fqdn string = !disableIngress ? containerApp.properties.configuration.ingress.fqdn : '' + +@description('System-assigned identity principal ID.') +output principalId string = contains(containerApp.identity.type, 'SystemAssigned') ? containerApp.identity.principalId : '' diff --git a/infra/bicep/modules/compute/container-instance.bicep b/infra/bicep/modules/compute/container-instance.bicep new file mode 100644 index 00000000..e3d690ff --- /dev/null +++ b/infra/bicep/modules/compute/container-instance.bicep @@ -0,0 +1,119 @@ +// ============================================================================ +// Module: Azure Container Instance +// Description: Creates an Azure Container Instance group +// API: Microsoft.ContainerInstance/containerGroups@2025-09-01 +// ============================================================================ + +@description('Name of the container group.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Container image to deploy.') +param containerImage string + +@description('CPU cores for the container.') +param cpu int = 2 + +@description('Memory in GB for the container.') +param memoryInGB int = 4 + +@description('Port to expose.') +param port int = 8000 + +@description('Environment variables for the container.') +param environmentVariables array = [] + +@description('Operating system type.') +@allowed(['Linux', 'Windows']) +param osType string = 'Linux' + +@description('Restart policy.') +@allowed(['Always', 'OnFailure', 'Never']) +param restartPolicy string = 'Always' + +@description('Managed identity configuration.') +param managedIdentities object = {} + +@description('Image registry credentials.') +param imageRegistryCredentials array = [] + +@description('Subnet resource ID for VNet integration. If empty, public IP is used.') +param subnetResourceId string = '' + +@description('Availability zone for the container group. Use -1 for no zone.') +param availabilityZone int = -1 + +// ============================================================================ +// Variables +// ============================================================================ +var isPrivateNetworking = !empty(subnetResourceId) + +var identityConfig = empty(managedIdentities) ? { type: 'None' } : { + type: contains(managedIdentities, 'userAssignedResourceIds') ? 'UserAssigned' : 'SystemAssigned' + userAssignedIdentities: contains(managedIdentities, 'userAssignedResourceIds') ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, id) => union(cur, { '${id}': {} })) : null +} + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource containerGroup 'Microsoft.ContainerInstance/containerGroups@2025-09-01' = { + name: name + location: location + tags: tags + identity: identityConfig + zones: availabilityZone != -1 ? [string(availabilityZone)] : null + properties: { + osType: osType + restartPolicy: restartPolicy + containers: [ + { + name: name + properties: { + image: containerImage + resources: { + requests: { + cpu: cpu + memoryInGB: memoryInGB + } + } + ports: [ + { + port: port + protocol: 'TCP' + } + ] + environmentVariables: environmentVariables + } + } + ] + imageRegistryCredentials: imageRegistryCredentials + subnetIds: isPrivateNetworking ? [{ id: subnetResourceId }] : null + ipAddress: { + type: isPrivateNetworking ? 'Private' : 'Public' + ports: [ + { + port: port + protocol: 'TCP' + } + ] + dnsNameLabel: isPrivateNetworking ? null : name + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container group.') +output name string = containerGroup.name + +@description('The resource ID of the container group.') +output resourceId string = containerGroup.id + +@description('The IP address of the container group.') +output ipAddress string = containerGroup.properties.ipAddress.ip diff --git a/infra/bicep/modules/compute/container-registry.bicep b/infra/bicep/modules/compute/container-registry.bicep new file mode 100644 index 00000000..9566d218 --- /dev/null +++ b/infra/bicep/modules/compute/container-registry.bicep @@ -0,0 +1,75 @@ +// ============================================================================ +// Module: Azure Container Registry +// Description: Creates an Azure Container Registry +// API: Microsoft.ContainerRegistry/registries@2025-04-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the container registry.') +param name string = replace('cr${solutionName}', '-', '') + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the container registry.') +@allowed(['Basic', 'Standard', 'Premium']) +param sku string = 'Premium' + +@description('Enable admin user.') +param adminUserEnabled bool = false + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Export policy status.') +param exportPolicyStatus string = 'enabled' + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2025-04-01' = { + name: name + location: location + tags: tags + sku: { + name: sku + } + properties: { + adminUserEnabled: adminUserEnabled + publicNetworkAccess: publicNetworkAccess + dataEndpointEnabled: false + networkRuleBypassOptions: 'AzureServices' + policies: { + exportPolicy: { + status: exportPolicyStatus + } + retentionPolicy: { + status: 'enabled' + days: 7 + } + trustPolicy: { + status: 'disabled' + type: 'Notary' + } + } + zoneRedundancy: 'Disabled' + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the container registry.') +output name string = containerRegistry.name + +@description('The login server URL.') +output loginServer string = containerRegistry.properties.loginServer + +@description('The resource ID of the container registry.') +output resourceId string = containerRegistry.id \ No newline at end of file diff --git a/infra/bicep/modules/compute/function-app.bicep b/infra/bicep/modules/compute/function-app.bicep new file mode 100644 index 00000000..4756b20f --- /dev/null +++ b/infra/bicep/modules/compute/function-app.bicep @@ -0,0 +1,100 @@ +// ============================================================================ +// Module: Azure Function App +// Description: Creates an Azure Function App on Linux +// API: Microsoft.Web/sites@2024-04-01 +// ============================================================================ + +@description('Name of the function app.') +param name string + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('Resource ID of the App Service Plan.') +param serverFarmResourceId string + +@description('Resource ID of the storage account for function app.') +param storageAccountResourceId string + +@description('Name of the storage account.') +param storageAccountName string + +@description('Managed identity configuration.') +param managedIdentities object = { + systemAssigned: true +} + +@description('App settings as name-value pairs.') +param appSettings array = [] + +@description('Site configuration object.') +param siteConfig object = {} + +@description('Runtime stack.') +param runtimeStack string = 'python' + +@description('Runtime version.') +param runtimeVersion string = '3.11' + +// ============================================================================ +// Variables +// ============================================================================ +var identityConfig = empty(managedIdentities) ? null : { + type: contains(managedIdentities, 'userAssignedResourceIds') ? (contains(managedIdentities, 'systemAssigned') && managedIdentities.systemAssigned ? 'SystemAssigned,UserAssigned' : 'UserAssigned') : 'SystemAssigned' + userAssignedIdentities: contains(managedIdentities, 'userAssignedResourceIds') ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, id) => union(cur, { '${id}': {} })) : null +} + +var storageConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};AccountKey=${listKeys(storageAccountResourceId, '2023-05-01').keys[0].value};EndpointSuffix=${environment().suffixes.storage}' +var linuxFxVersion = '${toUpper(runtimeStack)}|${runtimeVersion}' + +var baseSettings = [ + { name: 'AzureWebJobsStorage', value: storageConnectionString } + { name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' } + { name: 'FUNCTIONS_WORKER_RUNTIME', value: toLower(runtimeStack) } + { name: 'WEBSITE_RUN_FROM_PACKAGE', value: '1' } +] + +var mergedSettings = concat(baseSettings, appSettings) + +var defaultSiteConfig = { + linuxFxVersion: linuxFxVersion + ftpsState: 'Disabled' + minTlsVersion: '1.2' + appSettings: mergedSettings +} + +var effectiveSiteConfig = union(defaultSiteConfig, siteConfig) + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource functionApp 'Microsoft.Web/sites@2024-04-01' = { + name: name + location: location + tags: tags + kind: 'functionapp,linux' + identity: identityConfig + properties: { + serverFarmId: serverFarmResourceId + siteConfig: effectiveSiteConfig + httpsOnly: true + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the function app.') +output name string = functionApp.name + +@description('The resource ID of the function app.') +output resourceId string = functionApp.id + +@description('The default hostname of the function app.') +output defaultHostName string = functionApp.properties.defaultHostName + +@description('The principal ID of the system-assigned managed identity.') +output principalId string = contains(functionApp.identity, 'principalId') ? functionApp.identity.principalId : '' diff --git a/infra/bicep/modules/compute/kubernetes.bicep b/infra/bicep/modules/compute/kubernetes.bicep new file mode 100644 index 00000000..a12df945 --- /dev/null +++ b/infra/bicep/modules/compute/kubernetes.bicep @@ -0,0 +1,134 @@ +// ============================================================================ +// Module: Azure Kubernetes Service (AKS) +// Description: Deploys Azure Kubernetes Service Managed Cluster +// API: Microsoft.ContainerService/managedClusters@2025-03-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the AKS cluster.') +param name string = 'aks-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Kubernetes version for the cluster.') +param kubernetesVersion string = '1.34' + +@description('Agent pool configurations. Each entry requires name, vmSize, count, mode (System/User).') +param agentPools array = [ + { + name: 'systempool' + vmSize: 'Standard_D4ds_v5' + count: 2 + minCount: 1 + maxCount: 3 + enableAutoScaling: true + osType: 'Linux' + mode: 'System' + } +] + +@description('Enable Kubernetes RBAC.') +param enableRBAC bool = true + +@description('Disable local accounts (enforce AAD-only).') +param disableLocalAccounts bool = false + +@description('Network plugin for the cluster.') +@allowed(['azure', 'kubenet', 'none']) +param networkPlugin string = 'azure' + +@description('Network policy for the cluster.') +@allowed(['azure', 'calico', '']) +param networkPolicy string = 'azure' + +@description('DNS prefix for the cluster.') +param dnsPrefix string = '' + +@description('SKU tier for the cluster.') +@allowed(['Free', 'Standard', 'Premium']) +param skuTier string = 'Standard' + +@description('Service CIDR for Kubernetes services.') +param serviceCidr string = '10.20.0.0/16' + +@description('DNS service IP (must be within serviceCidr).') +param dnsServiceIP string = '10.20.0.10' + +@description('Auto-upgrade channel for the cluster.') +@allowed(['none', 'patch', 'rapid', 'stable', 'node-image']) +param autoUpgradeChannel string = 'stable' + +@description('Log Analytics workspace resource ID for monitoring.') +param logAnalyticsWorkspaceResourceId string = '' + +// ============================================================================ +// Variables +// ============================================================================ +var effectiveDnsPrefix = !empty(dnsPrefix) ? dnsPrefix : name + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource aksCluster 'Microsoft.ContainerService/managedClusters@2025-03-01' = { + name: name + location: location + tags: tags + identity: { + type: 'SystemAssigned' + } + sku: { + name: 'Base' + tier: skuTier + } + properties: { + kubernetesVersion: kubernetesVersion + dnsPrefix: effectiveDnsPrefix + enableRBAC: enableRBAC + disableLocalAccounts: disableLocalAccounts + agentPoolProfiles: [for pool in agentPools: { + name: pool.name + vmSize: pool.vmSize + count: pool.count + minCount: pool.?enableAutoScaling == true ? pool.?minCount : null + maxCount: pool.?enableAutoScaling == true ? pool.?maxCount : null + enableAutoScaling: pool.?enableAutoScaling ?? false + osType: pool.?osType ?? 'Linux' + mode: pool.mode + }] + networkProfile: { + networkPlugin: networkPlugin + networkPolicy: !empty(networkPolicy) ? networkPolicy : null + serviceCidr: serviceCidr + dnsServiceIP: dnsServiceIP + } + autoUpgradeProfile: { + upgradeChannel: autoUpgradeChannel + } + addonProfiles: !empty(logAnalyticsWorkspaceResourceId) ? { + omsagent: { + enabled: true + config: { + logAnalyticsWorkspaceResourceID: logAnalyticsWorkspaceResourceId + } + } + } : {} + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the AKS cluster.') +output name string = aksCluster.name + +@description('Resource ID of the AKS cluster.') +output resourceId string = aksCluster.id + +@description('FQDN of the AKS cluster.') +output fqdn string = aksCluster.properties.fqdn diff --git a/infra/bicep/modules/data/app-configuration.bicep b/infra/bicep/modules/data/app-configuration.bicep new file mode 100644 index 00000000..6df7aea1 --- /dev/null +++ b/infra/bicep/modules/data/app-configuration.bicep @@ -0,0 +1,63 @@ +// ============================================================================ +// Module: Azure App Configuration +// Description: Creates an Azure App Configuration store +// API: Microsoft.AppConfiguration/configurationStores@2023-03-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the App Configuration store.') +param name string = 'appcs-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU for the configuration store.') +@allowed(['Free', 'Standard']) +param sku string = 'Standard' + +@description('Disable local (key-based) authentication.') +param disableLocalAuth bool = true + +@description('Key-value pairs to store in the configuration.') +param keyValues array = [] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = { + name: name + location: location + tags: tags + sku: { + name: sku + } + properties: { + disableLocalAuth: disableLocalAuth + publicNetworkAccess: 'Enabled' + } +} + +resource configurationKeyValues 'Microsoft.AppConfiguration/configurationStores/keyValues@2023-03-01' = [for keyValue in keyValues: { + name: keyValue.name + parent: appConfiguration + properties: { + value: keyValue.value + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the App Configuration store.') +output name string = appConfiguration.name + +@description('The endpoint of the App Configuration store.') +output endpoint string = appConfiguration.properties.endpoint + +@description('The resource ID of the App Configuration store.') +output resourceId string = appConfiguration.id diff --git a/infra/bicep/modules/data/cosmos-db-mongo.bicep b/infra/bicep/modules/data/cosmos-db-mongo.bicep new file mode 100644 index 00000000..620c2f63 --- /dev/null +++ b/infra/bicep/modules/data/cosmos-db-mongo.bicep @@ -0,0 +1,114 @@ +// ============================================================================ +// Module: Cosmos DB (MongoDB) +// Description: Creates an Azure Cosmos DB account with MongoDB API +// API: Microsoft.DocumentDB/databaseAccounts@2025-10-15 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('MongoDB database name.') +param databaseName string = 'default' + +@description('MongoDB collections to create.') +param collections array = [] + +@description('MongoDB server version.') +@allowed(['4.2', '5.0', '6.0', '7.0']) +param serverVersion string = '7.0' + +@description('Default consistency level.') +@allowed(['Eventual', 'ConsistentPrefix', 'Session', 'BoundedStaleness', 'Strong']) +param consistencyLevel string = 'Session' + +@description('Enable analytical storage (Synapse Link).') +param enableAnalyticalStorage bool = false + +@description('Enable zone redundancy.') +param zoneRedundant bool = false + +@description('Enable automatic failover.') +param enableAutomaticFailover bool = false + +@description('HA paired region for multi-region failover.') +param haLocation string = '' + +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' = { + name: name + location: location + tags: tags + kind: 'MongoDB' + properties: { + consistencyPolicy: { defaultConsistencyLevel: consistencyLevel } + locations: zoneRedundant && !empty(haLocation) + ? [ + { locationName: location, failoverPriority: 0, isZoneRedundant: true } + { locationName: haLocation, failoverPriority: 1, isZoneRedundant: true } + ] + : [ + { locationName: location, failoverPriority: 0, isZoneRedundant: zoneRedundant } + ] + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: enableAutomaticFailover + enableMultipleWriteLocations: false + apiProperties: { serverVersion: serverVersion } + enableAnalyticalStorage: enableAnalyticalStorage + capabilities: [{ name: 'EnableMongo' }] + publicNetworkAccess: publicNetworkAccess + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-10-15' = { + parent: cosmos + name: databaseName + properties: { + resource: { id: databaseName } + } +} + +resource mongoCollections 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-10-15' = [for collection in collections: { + parent: database + name: collection.name + properties: { + resource: { + id: collection.name + shardKey: collection.?shardKey ?? {} + indexes: collection.?indexes ?? [ + { key: { keys: ['_id'] } } + ] + } + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmos.id + +@description('Name of the Cosmos DB account.') +output name string = cosmos.name + +@description('MongoDB connection string (without credentials — use Key Vault for secrets).') +output connectionString string = 'mongodb+srv://${name}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000' + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.mongo.cosmos.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName diff --git a/infra/bicep/modules/data/cosmos-db-nosql.bicep b/infra/bicep/modules/data/cosmos-db-nosql.bicep new file mode 100644 index 00000000..9c758c2e --- /dev/null +++ b/infra/bicep/modules/data/cosmos-db-nosql.bicep @@ -0,0 +1,90 @@ +// ============================================================================ +// Module: Cosmos DB +// Description: Creates an Azure Cosmos DB (NoSQL) account with database/container +// API: Microsoft.DocumentDB/databaseAccounts@2025-10-15 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Cosmos DB account.') +param name string = 'cosmos-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Database name.') +param databaseName string = 'db_conversation_history' + +@description('Container definitions.') +param containers array = [ + { + name: 'conversations' + partitionKeyPath: '/userId' + } +] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' = { + name: name + location: location + tags: tags + kind: 'GlobalDocumentDB' + properties: { + consistencyPolicy: { defaultConsistencyLevel: 'Session' } + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + enableMultipleWriteLocations: false + disableLocalAuth: true + capabilities: [ { name: 'EnableServerless' } ] + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-10-15' = { + parent: cosmos + name: databaseName + properties: { + resource: { id: databaseName } + } + + resource list 'containers' = [for container in containers: { + name: container.name + properties: { + resource: { + id: container.name + partitionKey: { paths: [ container.partitionKeyPath ] } + } + options: {} + } + }] +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Cosmos DB account.') +output resourceId string = cosmos.id + +@description('Name of the Cosmos DB account.') +output name string = cosmos.name + +@description('Endpoint of the Cosmos DB account.') +output endpoint string = 'https://${name}.documents.azure.com:443/' + +@description('Database name.') +output databaseName string = databaseName + +@description('Container name (first container).') +output containerName string = containers[0].name diff --git a/infra/bicep/modules/data/event-grid.bicep b/infra/bicep/modules/data/event-grid.bicep new file mode 100644 index 00000000..724481e1 --- /dev/null +++ b/infra/bicep/modules/data/event-grid.bicep @@ -0,0 +1,81 @@ +// ============================================================================ +// Module: Azure Event Grid System Topic +// Description: Deploys Azure Event Grid System Topic +// API: Microsoft.EventGrid/systemTopics@2025-07-15-preview +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the Event Grid System Topic.') +param name string = 'evgt-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the source that publishes events (e.g., Storage Account resource ID).') +param source string + +@description('The type of the event source. E.g., Microsoft.Storage.StorageAccounts.') +param topicType string + +@description('Event subscriptions to create on the system topic.') +param eventSubscriptions array = [] + +@description('Managed identities configuration. E.g., { systemAssigned: false, userAssignedResourceIds: [] }.') +param managedIdentities object = {} + +// ============================================================================ +// Resource +// ============================================================================ +resource eventGridSystemTopic 'Microsoft.EventGrid/systemTopics@2025-07-15-preview' = { + name: name + location: location + tags: tags + identity: !empty(managedIdentities) ? { + type: (managedIdentities.?systemAssigned ?? false) && !empty(managedIdentities.?userAssignedResourceIds ?? []) + ? 'SystemAssigned,UserAssigned' + : (managedIdentities.?systemAssigned ?? false) ? 'SystemAssigned' : 'UserAssigned' + userAssignedIdentities: !empty(managedIdentities.?userAssignedResourceIds ?? []) + ? reduce(managedIdentities.userAssignedResourceIds, {}, (cur, next) => union(cur, { '${next}': {} })) + : null + } : null + properties: { + source: source + topicType: topicType + } +} + +// ============================================================================ +// Event Subscriptions +// ============================================================================ +resource systemTopicSubscriptions 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2025-07-15-preview' = [ + for sub in eventSubscriptions: { + name: sub.name + parent: eventGridSystemTopic + properties: { + destination: sub.destination + filter: sub.?filter ?? {} + eventDeliverySchema: sub.?eventDeliverySchema ?? 'EventGridSchema' + retryPolicy: sub.?retryPolicy ?? { + maxDeliveryAttempts: 30 + eventTimeToLiveInMinutes: 1440 + } + } + } +] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the Event Grid System Topic.') +output name string = eventGridSystemTopic.name + +@description('Resource ID of the Event Grid System Topic.') +output resourceId string = eventGridSystemTopic.id + +@description('System-assigned principal ID (if enabled).') +output systemAssignedMIPrincipalId string = (managedIdentities.?systemAssigned ?? false) ? eventGridSystemTopic.identity.principalId : '' diff --git a/infra/bicep/modules/data/event-hub.bicep b/infra/bicep/modules/data/event-hub.bicep new file mode 100644 index 00000000..1dfb8a89 --- /dev/null +++ b/infra/bicep/modules/data/event-hub.bicep @@ -0,0 +1,62 @@ +// ============================================================================ +// Module: Azure Event Hub Namespace +// Description: Creates an Azure Event Hub Namespace with event hubs +// API: Microsoft.EventHub/namespaces@2024-01-01 +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Name of the Event Hub namespace.') +param name string = 'evhns-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('The SKU tier for the Event Hub namespace.') +param sku string = 'Standard' + +@description('The throughput unit or processing unit capacity.') +param capacity int = 1 + +@description('Event hubs to create within the namespace.') +param eventhubs array = [] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource eventHubNamespace 'Microsoft.EventHub/namespaces@2024-01-01' = { + name: name + location: location + tags: tags + sku: { + name: sku + tier: sku + capacity: capacity + } + properties: { + minimumTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + } +} + +resource eventHubResources 'Microsoft.EventHub/namespaces/eventhubs@2024-01-01' = [for eventhub in eventhubs: { + name: eventhub.name + parent: eventHubNamespace + properties: { + messageRetentionInDays: eventhub.?messageRetentionInDays ?? 1 + partitionCount: eventhub.?partitionCount ?? 2 + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('The name of the Event Hub namespace.') +output name string = eventHubNamespace.name + +@description('The resource ID of the Event Hub namespace.') +output resourceId string = eventHubNamespace.id diff --git a/infra/bicep/modules/data/postgresql-flexible-server.bicep b/infra/bicep/modules/data/postgresql-flexible-server.bicep new file mode 100644 index 00000000..3c6cb0eb --- /dev/null +++ b/infra/bicep/modules/data/postgresql-flexible-server.bicep @@ -0,0 +1,133 @@ +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the PostgreSQL Flexible Server.') +param name string = 'psql-${solutionName}' + +@description('The Azure region where the PostgreSQL Flexible Server will be deployed.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Azure AD administrators for the server. Each entry requires objectId, principalName, and principalType (User, Group, or ServicePrincipal).') +param administrators array + +@description('The PostgreSQL version to deploy.') +param version string = '16' + +@description('The SKU name for the PostgreSQL Flexible Server.') +param skuName string = 'Standard_B1ms' + +@description('The SKU tier for the PostgreSQL Flexible Server.') +@allowed(['Burstable', 'GeneralPurpose', 'MemoryOptimized']) +param skuTier string = 'Burstable' + +@description('The storage size in GB.') +param storageSizeGB int = 32 + +@description('Optional databases to create on the server. Each entry should have a name, and optionally charset and collation.') +param databases array = [] + +@description('Optional server configurations (e.g., extensions). Each entry should have a name, value, and source.') +param configurations array = [] + +resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2026-01-01-preview' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: skuTier + } + properties: { + version: version + storage: { + storageSizeGB: storageSizeGB + } + authConfig: { + activeDirectoryAuth: 'Enabled' + passwordAuth: 'Disabled' + } + highAvailability: { + mode: 'Disabled' + } + network: { + publicNetworkAccess: 'Enabled' + } + } +} + +resource firewallAllowAzureIPs 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2026-01-01-preview' = { + name: 'AllowAllAzureServicesAndResourcesWithinAzureIps' + parent: postgresServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } +} + +resource firewallAllowAll 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2026-01-01-preview' = { + name: 'AllowAll' + parent: postgresServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } +} + +// AAD admins must wait for firewall rules — server needs to be fully accessible first +@batchSize(1) +resource postgresAdmins 'Microsoft.DBforPostgreSQL/flexibleServers/administrators@2026-01-01-preview' = [ + for admin in administrators: { + parent: postgresServer + name: admin.objectId + dependsOn: [ + firewallAllowAzureIPs + firewallAllowAll + ] + properties: { + principalName: admin.principalName + principalType: admin.principalType + tenantId: subscription().tenantId + } + } +] + +resource serverDatabases 'Microsoft.DBforPostgreSQL/flexibleServers/databases@2026-01-01-preview' = [ + for db in databases: { + name: db.name + parent: postgresServer + properties: { + charset: db.?charset ?? 'UTF8' + collation: db.?collation ?? 'en_US.utf8' + } + dependsOn: [ + postgresAdmins + ] + } +] + +@batchSize(1) +resource serverConfigurations 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2026-01-01-preview' = [ + for config in configurations: { + name: config.name + parent: postgresServer + properties: { + value: config.value + source: config.source + } + dependsOn: [ + postgresAdmins + ] + } +] + +@description('The fully qualified domain name of the PostgreSQL Flexible Server.') +output serverFqdn string = postgresServer.properties.fullyQualifiedDomainName + +@description('The name of the PostgreSQL Flexible Server.') +output name string = postgresServer.name + +@description('The resource ID of the PostgreSQL Flexible Server.') +output resourceId string = postgresServer.id diff --git a/infra/bicep/modules/data/sql-database.bicep b/infra/bicep/modules/data/sql-database.bicep new file mode 100644 index 00000000..2e647c1e --- /dev/null +++ b/infra/bicep/modules/data/sql-database.bicep @@ -0,0 +1,115 @@ +// ============================================================================ +// Module: SQL Database +// Description: Creates an Azure SQL Server and Database +// API: Microsoft.Sql/servers@2025-01-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the SQL Server.') +param name string = 'sql-${solutionName}' + +@description('Name of the SQL Database.') +param databaseName string = 'sqldb-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Principal ID of the deployer for admin access.') +param deployerPrincipalId string + +@description('SKU name for the database.') +param skuName string = 'GP_S_Gen5' + +@description('SKU tier for the database.') +param skuTier string = 'GeneralPurpose' + +@description('SKU family.') +param skuFamily string = 'Gen5' + +@description('vCore capacity.') +param skuCapacity int = 2 + +@description('Auto-pause delay in minutes.') +param autoPauseDelay int = 60 + +@description('Minimum capacity (vCores).') +param minCapacity int = 1 + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource sqlServer 'Microsoft.Sql/servers@2025-01-01' = { + name: name + location: location + tags: tags + properties: { + publicNetworkAccess: 'Enabled' + version: '12.0' + restrictOutboundNetworkAccess: 'Disabled' + minimalTlsVersion: '1.2' + administrators: { + login: deployerPrincipalId + sid: deployerPrincipalId + tenantId: subscription().tenantId + administratorType: 'ActiveDirectory' + azureADOnlyAuthentication: true + } + } +} + +resource firewallRule 'Microsoft.Sql/servers/firewallRules@2025-01-01' = { + name: 'AllowSpecificRange' + parent: sqlServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } +} + +resource AllowAllWindowsAzureIps 'Microsoft.Sql/servers/firewallRules@2025-01-01' = { + name: 'AllowAllWindowsAzureIps' + parent: sqlServer + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } +} + +resource sqlDB 'Microsoft.Sql/servers/databases@2025-01-01' = { + parent: sqlServer + name: databaseName + location: location + sku: { + name: skuName + tier: skuTier + family: skuFamily + capacity: skuCapacity + } + properties: { + collation: 'SQL_Latin1_General_CP1_CI_AS' + autoPauseDelay: autoPauseDelay + minCapacity: minCapacity + readScale: 'Disabled' + zoneRedundant: false + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Fully qualified domain name of the SQL Server.') +output serverFqdn string = '${name}.database.windows.net' + +@description('Name of the SQL Database.') +output databaseName string = databaseName + +@description('Resource ID of the SQL Server.') +output serverResourceId string = sqlServer.id + +@description('Name of the SQL Server.') +output name string = sqlServer.name diff --git a/infra/bicep/modules/data/storage-account.bicep b/infra/bicep/modules/data/storage-account.bicep new file mode 100644 index 00000000..ea9d5386 --- /dev/null +++ b/infra/bicep/modules/data/storage-account.bicep @@ -0,0 +1,101 @@ +// ============================================================================ +// Module: Storage Account +// Description: Creates an Azure Storage Account with blob container +// API: Microsoft.Storage/storageAccounts@2025-08-01 +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the storage account.') +param name string = take('st${toLower(replace(solutionName, '-', ''))}', 24) + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Storage account SKU.') +param skuName string = 'Standard_LRS' + +@description('Storage account kind.') +param kind string = 'StorageV2' + +@description('Access tier.') +@allowed(['Hot', 'Cool']) +param accessTier string = 'Hot' + +@description('Allow blob public access.') +param allowBlobPublicAccess bool = false + +@description('Allow shared key access.') +param allowSharedKeyAccess bool = true + +@description('Blob containers to create.') +param containers array = [ + { + name: 'default' + publicAccess: 'None' + } +] + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' = { + name: name + location: location + tags: tags + kind: kind + sku: { + name: skuName + } + properties: { + accessTier: accessTier + allowBlobPublicAccess: allowBlobPublicAccess + allowSharedKeyAccess: allowSharedKeyAccess + minimumTlsVersion: 'TLS1_2' + supportsHttpsTrafficOnly: true + encryption: { + services: { + blob: { + enabled: true + } + file: { + enabled: true + } + } + keySource: 'Microsoft.Storage' + requireInfrastructureEncryption: true + } + } +} + +resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2025-08-01' = { + parent: storageAccount + name: 'default' +} + +resource blobContainers 'Microsoft.Storage/storageAccounts/blobServices/containers@2025-08-01' = [for container in containers: { + parent: blobService + name: container.name + properties: { + publicAccess: container.publicAccess + } +}] + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the Storage Account.') +output resourceId string = storageAccount.id + +@description('Name of the Storage Account.') +output name string = storageAccount.name + +@description('Primary blob endpoint.') +output blobEndpoint string = storageAccount.properties.primaryEndpoints.blob + +@description('All service endpoints.') +output serviceEndpoints object = storageAccount.properties.primaryEndpoints diff --git a/infra/bicep/modules/fabric/fabric-capacity.bicep b/infra/bicep/modules/fabric/fabric-capacity.bicep new file mode 100644 index 00000000..17f6498b --- /dev/null +++ b/infra/bicep/modules/fabric/fabric-capacity.bicep @@ -0,0 +1,72 @@ +// ============================================================================ +// Module: Fabric Capacity +// Description: Vanilla Bicep module for Microsoft Fabric Capacity +// Resource: Microsoft.Fabric/capacities@2023-11-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.fabric/capacities +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Fabric capacity. Defaults to fc{solutionName}.') +param name string = 'fc${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('SKU tier of the Fabric capacity.') +@allowed([ + 'F2' + 'F4' + 'F8' + 'F16' + 'F32' + 'F64' + 'F128' + 'F256' + 'F512' + 'F1024' + 'F2048' +]) +param skuName string = 'F2' + +@description('List of admin members (UPNs for users, object IDs for service principals).') +param adminMembers array + +// ============================================================================ +// Resource +// ============================================================================ + +resource fabricCapacity 'Microsoft.Fabric/capacities@2023-11-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: 'Fabric' + } + properties: { + administration: { + members: adminMembers + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the deployed Fabric capacity.') +output name string = fabricCapacity.name + +@description('The resource ID of the deployed Fabric capacity.') +output resourceId string = fabricCapacity.id + +@description('The resource group name.') +output resourceGroupName string = resourceGroup().name + +@description('The location of the deployed Fabric capacity.') +output location string = fabricCapacity.location diff --git a/infra/bicep/modules/identity/cross-scope-role-assignment.bicep b/infra/bicep/modules/identity/cross-scope-role-assignment.bicep new file mode 100644 index 00000000..19e43cc0 --- /dev/null +++ b/infra/bicep/modules/identity/cross-scope-role-assignment.bicep @@ -0,0 +1,37 @@ +// ============================================================================ +// cross-scope-role-assignment.bicep +// Description: Reusable helper that creates a single role assignment scoped +// to an existing AI Services resource. Used for cross-resource- +// group RBAC where the AI Services lives in a different RG. +// ============================================================================ + +@description('The principal ID to assign the role to.') +param principalId string + +@description('The resource ID of the role definition to assign.') +param roleDefinitionId string + +@description('A unique name for the role assignment.') +param roleAssignmentName string + +@description('The name of the AI Services account to scope the role assignment to.') +param aiFoundryName string + +@description('The principal type of the identity being assigned.') +@allowed(['ServicePrincipal', 'User']) +param principalType string = 'ServicePrincipal' + +// Reference the existing AI Services resource in this resource group +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiFoundryName +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: roleAssignmentName + scope: aiServices + properties: { + roleDefinitionId: roleDefinitionId + principalId: principalId + principalType: principalType + } +} diff --git a/infra/bicep/modules/identity/managed-identity.bicep b/infra/bicep/modules/identity/managed-identity.bicep new file mode 100644 index 00000000..e8accb80 --- /dev/null +++ b/infra/bicep/modules/identity/managed-identity.bicep @@ -0,0 +1,43 @@ +// ============================================================================ +// Module: User-Assigned Managed Identity (Generic) +// Description: Creates a user-assigned managed identity. +// This module is NOT called from main.bicep by default. +// Use it when you need a user-assigned identity for specific scenarios +// (e.g., Container Apps, cross-tenant access, pre-provisioned RBAC). +// ============================================================================ + +@description('Solution name used for resource naming.') +param solutionName string + +@description('Name of the managed identity.') +param identityName string = 'id-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +// ============================================================================ +// Resource Deployment +// ============================================================================ +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: identityName + location: location + tags: tags +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the managed identity.') +output resourceId string = managedIdentity.id + +@description('Principal ID (object ID) of the managed identity.') +output principalId string = managedIdentity.properties.principalId + +@description('Client ID of the managed identity.') +output clientId string = managedIdentity.properties.clientId + +@description('Name of the managed identity.') +output name string = managedIdentity.name diff --git a/infra/bicep/modules/identity/role-assignments.bicep b/infra/bicep/modules/identity/role-assignments.bicep new file mode 100644 index 00000000..00559492 --- /dev/null +++ b/infra/bicep/modules/identity/role-assignments.bicep @@ -0,0 +1,350 @@ +// ============================================================================ +// Module: Role Assignments (centralized — all cross-service + data plane RBAC) +// Description: RG-level, cross-service, and data-plane role assignments. +// One place to audit "who has access to what". +// ============================================================================ + +// ============================================================================ +// Parameters +// ============================================================================ + +@description('Solution name suffix for generating unique role assignment GUIDs.') +param solutionName string = '' + +@description('Whether to use an existing AI project (true) or create new (false).') +param useExistingAIProject bool = false + +@description('Resource ID of the existing AI project (for deriving AI Services name/sub/RG).') +param existingFoundryProjectResourceId string = '' + +// --- Identity Principal IDs --- + +@description('Principal ID of the AI project identity.') +param aiProjectPrincipalId string = '' + +@description('Principal ID of the existing AI project identity (for cross-service roles).') +param existingAiProjectPrincipalId string = '' + +@description('Principal ID of the AI Search identity.') +param aiSearchPrincipalId string = '' + +@description('Principal ID of the backend App Service system-assigned identity (empty if not deployed).') +param backendAppServicePrincipalId string = '' + +@description('Principal ID of the deploying user (for user access roles).') +param deployerPrincipalId string = '' + +@description('Principal type of the deploying user.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + +// --- Resource References --- + +@description('Resource ID of the AI Foundry account (empty if not deployed — new project path).') +param aiFoundryResourceId string = '' + +@description('Resource ID of the AI Search service (empty if not deployed).') +param aiSearchResourceId string = '' + +@description('Resource ID of the Storage Account (empty if not deployed).') +param storageAccountResourceId string = '' + +@description('Name of the Cosmos DB account (empty if not deployed).') +param cosmosDbAccountName string = '' + +// ============================================================================ +// Derived Variables +// ============================================================================ + +var existingAIFoundryName = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[8] : '' +var existingAIFoundrySubscription = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[2] : subscription().subscriptionId +var existingAIFoundryResourceGroup = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[4] : resourceGroup().name + +// ============================================================================ +// Role Definitions +// ============================================================================ + +var roleDefinitions = { + azureAiUser: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Foundry User + cognitiveServicesUser: 'a97b65f3-24c7-4388-baec-2e87135dc908' + cognitiveServicesOpenAIUser: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + searchIndexDataReader: '1407120a-92aa-4202-b7e9-c0e197c71c8f' + searchIndexDataContributor: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' + searchServiceContributor: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' + storageBlobDataContributor: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + storageBlobDataReader: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +} + +// ============================================================================ +// Existing Resource References +// ============================================================================ + +resource aiFoundryAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if (!empty(aiFoundryResourceId)) { + name: last(split(aiFoundryResourceId, '/')) +} + +resource aiSearchService 'Microsoft.Search/searchServices@2025-05-01' existing = if (!empty(aiSearchResourceId)) { + name: last(split(aiSearchResourceId, '/')) +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' existing = if (!empty(storageAccountResourceId)) { + name: last(split(storageAccountResourceId, '/')) +} + +resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + name: cosmosDbAccountName +} + +resource cosmosContributorRoleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { + parent: cosmosAccount + name: '00000000-0000-0000-0000-000000000002' // Cosmos DB Built-in Data Contributor +} + +// ============================================================================ +// 1. AI SERVICES ROLE ASSIGNMENTS +// Cross-service roles scoped to AI Foundry account +// ============================================================================ + +// AI Search → Cognitive Services OpenAI User on AI Foundry (new project, same RG) +resource assignOpenAIRoleToAISearch 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiSearchPrincipalId) && !empty(aiFoundryResourceId)) { + name: guid(aiFoundryAccount.id, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + scope: aiFoundryAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Cognitive Services OpenAI User on existing AI Foundry (cross-scope) +module assignOpenAIToSearchExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(aiSearchPrincipalId)) { + name: 'assignOpenAIRoleToAISearchExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + roleAssignmentName: guid(existingAIFoundryName, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + aiFoundryName: existingAIFoundryName + } +} + +// Backend App Service → Foundry User on AI Foundry (new project, same RG) +resource backendAppAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiFoundryResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiFoundryAccount.id, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + scope: aiFoundryAccount + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Foundry User on existing AI Foundry (cross-scope) +module backendAppAiUserExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(backendAppServicePrincipalId)) { + name: 'assignAiUserRoleToBackendExisting' + scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) + params: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + roleAssignmentName: guid(existingAIFoundryName, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + aiFoundryName: existingAIFoundryName + } +} + +// ============================================================================ +// 2. SEARCH SERVICE ROLE ASSIGNMENTS +// AI Project and Backend identities → AI Search +// ============================================================================ + +// AI Project → Search Index Data Reader on AI Search (new project) +resource projectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Search Service Contributor on AI Search (new project) +resource projectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Index Data Reader on AI Search +resource existingProjectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Search Service Contributor on AI Search +resource existingProjectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchServiceContributor) + scope: aiSearchService + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: 'ServicePrincipal' + } +} + +// Backend App Service → Search Index Data Reader on AI Search +resource backendAppSearchReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(backendAppServicePrincipalId)) { + name: guid(aiSearchService.id, backendAppServicePrincipalId, roleDefinitions.searchIndexDataReader) + scope: aiSearchService + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 3. STORAGE ROLE ASSIGNMENTS +// AI Project, AI Search, and Existing Project identities → Storage +// ============================================================================ + +// AI Project → Storage Blob Data Contributor (new project) +resource projectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// AI Project → Storage Blob Data Reader (new project) +resource projectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { + name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Contributor +resource existingProjectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: 'ServicePrincipal' + } +} + +// Existing AI Project → Storage Blob Data Reader +resource existingProjectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { + name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: existingAiProjectPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// AI Search → Storage Blob Data Reader +resource searchStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiSearchPrincipalId)) { + name: guid(storageAccount.id, aiSearchPrincipalId, roleDefinitions.storageBlobDataReader) + scope: storageAccount + properties: { + principalId: aiSearchPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalType: 'ServicePrincipal' + } +} + +// ============================================================================ +// 4. COSMOS DB ROLE ASSIGNMENTS +// Backend App Service → Cosmos DB (data-plane, uses sqlRoleAssignments) +// ============================================================================ + +resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) { + parent: cosmosAccount + name: guid(cosmosContributorRoleDefinition.id, cosmosAccount.id, backendAppServicePrincipalId) + properties: { + principalId: backendAppServicePrincipalId + roleDefinitionId: cosmosContributorRoleDefinition.id + scope: cosmosAccount.id + } +} + +// ============================================================================ +// 5. DEPLOYER (USER) ROLE ASSIGNMENTS +// Deploying user → AI Services, Search, Storage (Bicep-only) +// ============================================================================ + +// Deploying User → Cognitive Services User on AI Services +resource deployerAiServicesAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(deployerPrincipalId) && !empty(aiFoundryResourceId)) { + scope: aiFoundryAccount + name: guid(aiFoundryAccount.id, deployerPrincipalId, roleDefinitions.cognitiveServicesUser) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesUser) + principalType: deployerPrincipalType + } +} + +// Deploying User → Foundry User on AI Services +resource deployerAzureAIAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(deployerPrincipalId) && !empty(aiFoundryResourceId)) { + scope: aiFoundryAccount + name: guid(aiFoundryAccount.id, deployerPrincipalId, roleDefinitions.azureAiUser) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) + principalType: deployerPrincipalType + } +} + +// Deploying User → Search Index Data Contributor on AI Search +resource deployerSearchIndexContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(aiSearchResourceId)) { + scope: aiSearchService + name: guid(aiSearchService.id, deployerPrincipalId, roleDefinitions.searchIndexDataContributor) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataContributor) + principalType: deployerPrincipalType + } +} + +// Deploying User → Search Service Contributor on AI Search +resource deployerSearchServiceContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(aiSearchResourceId)) { + scope: aiSearchService + name: guid(aiSearchService.id, deployerPrincipalId, roleDefinitions.searchServiceContributor) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalType: deployerPrincipalType + } +} + +// Deploying User → Storage Blob Data Contributor +resource deployerStorageBlobContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(storageAccountResourceId)) { + scope: storageAccount + name: guid(storageAccount.id, deployerPrincipalId, roleDefinitions.storageBlobDataContributor) + properties: { + principalId: deployerPrincipalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalType: deployerPrincipalType + } +} + +// NOTE: Deployer roles on existing AI Foundry (cross-scope) are assigned via +// 00_build_solution.py to avoid conflicts when the deployer already has the roles. diff --git a/infra/bicep/modules/monitoring/app-insights.bicep b/infra/bicep/modules/monitoring/app-insights.bicep new file mode 100644 index 00000000..f3ebe34b --- /dev/null +++ b/infra/bicep/modules/monitoring/app-insights.bicep @@ -0,0 +1,72 @@ +// ============================================================================ +// Module: Application Insights +// Description: Vanilla Bicep module for Application Insights +// Resource: Microsoft.Insights/components@2020-02-02 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.insights/components +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}.') +param name string = 'appi-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Resource ID of the Log Analytics workspace to link to.') +param workspaceResourceId string + +@description('Application type.') +param applicationType string = 'web' + +@description('Retention period in days.') +param retentionInDays int = 365 + +@description('Disable IP masking for security.') +param disableIpMasking bool = false + +@description('Flow type for Application Insights.') +param flowType string = 'Bluefield' + +// ============================================================================ +// Resource +// ============================================================================ + +resource appInsights 'Microsoft.Insights/components@2020-02-02' = { + name: name + location: location + tags: tags + kind: 'web' + properties: { + Application_Type: applicationType + Flow_Type: flowType + WorkspaceResourceId: workspaceResourceId + RetentionInDays: retentionInDays + DisableIpMasking: disableIpMasking + publicNetworkAccessForIngestion: 'Enabled' + publicNetworkAccessForQuery: 'Enabled' + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the Application Insights instance.') +output resourceId string = appInsights.id + +@description('Name of the Application Insights instance.') +output name string = appInsights.name + +@description('Instrumentation key for the Application Insights instance.') +output instrumentationKey string = appInsights.properties.InstrumentationKey + +@description('Connection string for the Application Insights instance.') +output connectionString string = appInsights.properties.ConnectionString + +@description('Application ID of the Application Insights instance.') +output applicationId string = appInsights.properties.AppId diff --git a/infra/bicep/modules/monitoring/log-analytics.bicep b/infra/bicep/modules/monitoring/log-analytics.bicep new file mode 100644 index 00000000..87d79740 --- /dev/null +++ b/infra/bicep/modules/monitoring/log-analytics.bicep @@ -0,0 +1,58 @@ +// ============================================================================ +// Module: Log Analytics Workspace +// Description: Vanilla Bicep module for Log Analytics Workspace +// Resource: Microsoft.OperationalInsights/workspaces@2023-09-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.operationalinsights/workspaces +// Note: This module only handles NEW workspace creation. +// Existing workspace logic is handled in main.bicep. +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}.') +param name string = 'log-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Retention period in days.') +param retentionInDays int = 365 + +@description('SKU name for the workspace.') +param skuName string = 'PerGB2018' + +// ============================================================================ +// Resource +// ============================================================================ + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: name + location: location + tags: tags + properties: { + retentionInDays: retentionInDays + sku: { + name: skuName + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('Resource ID of the Log Analytics workspace.') +output resourceId string = logAnalytics.id + +@description('Name of the Log Analytics workspace.') +output name string = logAnalytics.name + +@description('Location of the workspace.') +output location string = logAnalytics.location + +@description('Log Analytics workspace customer ID.') +output logAnalyticsWorkspaceId string = logAnalytics.properties.customerId diff --git a/infra/bicep/modules/monitoring/portal-dashboard.bicep b/infra/bicep/modules/monitoring/portal-dashboard.bicep new file mode 100644 index 00000000..c5c08ec8 --- /dev/null +++ b/infra/bicep/modules/monitoring/portal-dashboard.bicep @@ -0,0 +1,49 @@ +// ============================================================================ +// Module: Portal Dashboard (Application Insights) +// Description: Vanilla Bicep module for Azure Portal Dashboard +// Resource: Microsoft.Portal/dashboards@2025-04-01-preview +// Docs: https://learn.microsoft.com/azure/templates/microsoft.portal/dashboards +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Name of the dashboard.') +param name string = 'dash-${solutionName}' + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Lenses (tile groups) to display on the dashboard.') +param lenses array = [] + +@description('Dashboard metadata (time range, filters, etc.).') +param metadata object = {} + +// ============================================================================ +// Resource +// ============================================================================ +resource dashboard 'Microsoft.Portal/dashboards@2025-04-01-preview' = { + name: name + location: location + tags: tags + properties: { + lenses: lenses + metadata: !empty(metadata) ? metadata : {} + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Resource ID of the dashboard.') +output resourceId string = dashboard.id + +@description('Name of the dashboard.') +output name string = dashboard.name + +@description('Resource group the dashboard was deployed to.') +output resourceGroupName string = resourceGroup().name diff --git a/infra/bicep/modules/security/key-vault.bicep b/infra/bicep/modules/security/key-vault.bicep new file mode 100644 index 00000000..acd258db --- /dev/null +++ b/infra/bicep/modules/security/key-vault.bicep @@ -0,0 +1,81 @@ +// ============================================================================ +// Module: Azure Key Vault +// Description: Vanilla Bicep module for Azure Key Vault +// Resource: Microsoft.KeyVault/vaults@2023-07-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.keyvault/vaults +// ============================================================================ + +@description('Solution name used for naming convention.') +param solutionName string + +@description('Optional. Override name for the Key Vault. Defaults to kv-{solutionName}.') +param name string = take('kv-${solutionName}', 24) + +@description('Azure region for deployment.') +param location string + +@description('Resource tags.') +param tags object = {} + +@description('SKU for the key vault.') +@allowed(['standard', 'premium']) +param sku string = 'standard' + +@description('Enable RBAC authorization.') +param enableRbacAuthorization bool = true + +@description('Enable soft delete.') +param enableSoftDelete bool = true + +@description('Soft delete retention in days.') +param softDeleteRetentionInDays int = 90 + +@description('Enable purge protection.') +param enablePurgeProtection bool = true + +@description('Public network access setting.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('The Microsoft Entra tenant ID for the Key Vault.') +param tenantId string = subscription().tenantId + +// ============================================================================ +// Key Vault Resource +// ============================================================================ + +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { + name: name + location: location + tags: tags + properties: { + tenantId: tenantId + sku: { + family: 'A' + name: sku + } + accessPolicies: [] + enableRbacAuthorization: enableRbacAuthorization + enableSoftDelete: enableSoftDelete + softDeleteRetentionInDays: softDeleteRetentionInDays + enablePurgeProtection: enablePurgeProtection + publicNetworkAccess: publicNetworkAccess + networkAcls: { + bypass: 'AzureServices' + defaultAction: publicNetworkAccess == 'Disabled' ? 'Deny' : 'Allow' + } + } +} + +// ============================================================================ +// Outputs +// ============================================================================ + +@description('The name of the Key Vault.') +output name string = keyVault.name + +@description('The URI of the Key Vault.') +output uri string = keyVault.properties.vaultUri + +@description('The resource ID of the Key Vault.') +output resourceId string = keyVault.id From 6938400a938fe818d1d4b4aabc563b49b23f730f Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Wed, 10 Jun 2026 16:36:41 +0530 Subject: [PATCH 4/8] Add .gitkeep files to maintain directory structure for provisioning scripts --- infra/README.md | 91 + infra/avm/main.bicep | 1872 + infra/avm/main.json | 68661 ++++++++ infra/bicep/main.bicep | 794 + infra/bicep/main.json | 3406 + infra/main.bicep | 1935 +- infra/main.json | 121254 ++++++++------- infra/modules/account/aifoundry.bicep | 421 - .../account/modules/dependencies.bicep | 479 - .../account/modules/keyVaultExport.bicep | 43 - infra/modules/account/modules/project.bicep | 62 - infra/modules/container-registry.bicep | 92 - infra/modules/log-analytics-workspace.bicep | 105 - infra/modules/managed-identity.bicep | 25 - infra/modules/virtualNetwork.bicep | 397 - infra/scripts/post-provision/.gitkeep | 0 infra/scripts/pre-provision/.gitkeep | 0 infra/scripts/utilities/.gitkeep | 0 18 files changed, 138584 insertions(+), 61053 deletions(-) create mode 100644 infra/README.md create mode 100644 infra/avm/main.bicep create mode 100644 infra/avm/main.json create mode 100644 infra/bicep/main.bicep create mode 100644 infra/bicep/main.json delete mode 100644 infra/modules/account/aifoundry.bicep delete mode 100644 infra/modules/account/modules/dependencies.bicep delete mode 100644 infra/modules/account/modules/keyVaultExport.bicep delete mode 100644 infra/modules/account/modules/project.bicep delete mode 100644 infra/modules/container-registry.bicep delete mode 100644 infra/modules/log-analytics-workspace.bicep delete mode 100644 infra/modules/managed-identity.bicep delete mode 100644 infra/modules/virtualNetwork.bicep create mode 100644 infra/scripts/post-provision/.gitkeep create mode 100644 infra/scripts/pre-provision/.gitkeep create mode 100644 infra/scripts/utilities/.gitkeep diff --git a/infra/README.md b/infra/README.md new file mode 100644 index 00000000..cf65b97b --- /dev/null +++ b/infra/README.md @@ -0,0 +1,91 @@ +# Infrastructure — Content Processing Solution Accelerator + +This folder contains the Bicep/ARM infrastructure-as-code for the Content Processing Solution Accelerator. + +## Deployment Flavors + +| Flavor | Description | +|--------|-------------| +| `avm` | Azure Verified Modules — production-grade, non-WAF | +| `avm-waf` | AVM with WAF-aligned features (monitoring, private networking, scalability, redundancy) | +| `bicep` | Vanilla Bicep — direct ARM resource definitions | + +## Folder Structure + +``` +infra/ +├── main.bicep ← Deployment router (selects flavor) +├── main.json ← Compiled ARM template (used by CI/CD) +├── main.parameters.json ← Standard deployment parameters +├── main.waf.parameters.json ← WAF deployment parameters +├── main_custom.bicep ← Oryx source-code build variant (azd deploy) +├── avm/ +│ ├── main.bicep ← AVM orchestrator +│ ├── main.json ← Compiled ARM +│ └── modules/ +│ ├── ai/ ← AI Services, AI Search +│ ├── compute/ ← Container Registry +│ ├── identity/ ← Managed Identity +│ ├── monitoring/ ← Log Analytics +│ └── networking/ ← VNet, Bastion, Private DNS +├── bicep/ +│ ├── main.bicep ← Vanilla Bicep orchestrator +│ ├── main.json ← Compiled ARM +│ └── modules/ +│ ├── ai/ ← AI Services, Project, Model, Search +│ ├── compute/ ← Container Apps, Environment, Registry +│ ├── data/ ← Storage, Cosmos DB, App Configuration +│ ├── identity/ ← Managed Identity +│ └── monitoring/ ← Log Analytics, App Insights +├── scripts/ +│ ├── build/ ← Build-time scripts +│ ├── post-provision/ ← Post-provisioning hooks +│ ├── pre-provision/ ← Pre-provisioning hooks +│ └── utilities/ ← Utility scripts +└── azure.yaml ← azd infrastructure config +``` + +## Usage + +### Deploy with Azure Developer CLI (azd) + +```bash +# Standard deployment (AVM flavor) +azd up + +# WAF deployment +azd up --environment-values DEPLOYMENT_FLAVOR=avm-waf +``` + +### Deploy with Azure CLI + +```bash +az deployment group create \ + --resource-group \ + --template-file infra/main.json \ + --parameters infra/main.parameters.json +``` + +### Build ARM template from Bicep + +```bash +az bicep build --file infra/main.bicep --outfile infra/main.json +``` + +## Parameters + +| Parameter | Required | Description | +|-----------|:--------:|-------------| +| `deploymentFlavor` | No | `avm` (default), `bicep`, or `avm-waf` | +| `solutionName` | No | Solution name (3-20 chars), default: `cps` | +| `location` | Yes | Azure region for resources | +| `azureAiServiceLocation` | Yes | Azure region for AI Services | +| `gptModelName` | No | GPT model name, default: `gpt-5.1` | +| `deploymentType` | No | `GlobalStandard` (default) or `Standard` | +| `gptModelVersion` | No | Model version, default: `2025-11-13` | +| `gptDeploymentCapacity` | No | TPM capacity, default: `300` | +| `imageTag` | No | Container image tag, default: `latest_v2` | +| `enablePrivateNetworking` | No | Enable VNet/private endpoints | +| `enableMonitoring` | No | Enable Log Analytics + App Insights | +| `enableRedundancy` | No | Enable zone redundancy | +| `enableScalability` | No | Enable higher scale defaults | diff --git a/infra/avm/main.bicep b/infra/avm/main.bicep new file mode 100644 index 00000000..a492c376 --- /dev/null +++ b/infra/avm/main.bicep @@ -0,0 +1,1872 @@ +// ========== main.bicep ========== // +targetScope = 'resourceGroup' + +metadata name = 'Content Processing Solution Accelerator' +metadata description = 'Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance.' + +// ========== Parameters ========== // +@minLength(3) +@maxLength(20) +@description('Optional. Name of the solution to deploy. This should be 3-20 characters long.') +param solutionName string = 'cps' + +@metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).') +@allowed([ + 'australiaeast' + 'centralus' + 'eastasia' + 'eastus2' + 'japaneast' + 'northeurope' + 'southeastasia' + 'uksouth' +]) +param location string + +@minLength(1) +@allowed([ + 'australiaeast' + 'eastus' + 'eastus2' + 'japaneast' + 'southcentralus' + 'southeastasia' + 'swedencentral' + 'uksouth' + 'westeurope' + 'westus' + 'westus3' +]) +@description('Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead.') +@metadata({ + azd: { + type: 'location' + usageName: [ + 'OpenAI.GlobalStandard.gpt-5.1,300' + ] + } +}) +param azureAiServiceLocation string + +@description('Optional. Type of GPT deployment to use: Standard | GlobalStandard.') +@minLength(1) +@allowed([ + 'Standard' + 'GlobalStandard' +]) +param deploymentType string = 'GlobalStandard' + +@description('Optional. Name of the GPT model to deploy: gpt-5.1') +param gptModelName string = 'gpt-5.1' + +@minLength(1) +@description('Optional. Version of the GPT model to deploy:.') +@allowed([ + '2025-11-13' +]) +param gptModelVersion string = '2025-11-13' + +@minValue(1) +@description('Optional. Capacity of the GPT deployment: (minimum 10).') +param gptDeploymentCapacity int = 300 + +@description('Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint).') +param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' + +@description('Optional. The image tag for the container images.') +param imageTag string = 'latest_v2' + +@description('Optional. Enable WAF for the deployment.') +param enablePrivateNetworking bool = false + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') +param enableMonitoring bool = false + +@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableRedundancy bool = false + +@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableScalability bool = false + +@description('Optional. Enable purge protection. Defaults to false.') +param enablePurgeProtection bool = false + +@description('Optional. Tags to be applied to the resources.') +param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location +} + +@description('Optional: Existing Log Analytics Workspace Resource ID') +param existingLogAnalyticsWorkspaceId string = '' + +@description('Use this parameter to use an existing AI project resource ID') +param existingFoundryProjectResourceId string = '' + +@description('Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true.') +param vmSize string = '' + +@description('Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') +@secure() +param vmAdminUsername string = '' + +@description('Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') +@secure() +param vmAdminPassword string = '' + +@maxLength(5) +@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') +param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) + +var solutionSuffix = toLower(trim(replace( + replace( + replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), + ' ', + '' + ), + '*', + '' +))) +// ============== // +// Resources // +// ============== // + +var existingProjectResourceId = trim(existingFoundryProjectResourceId) + +// ========== AVM Telemetry ========== // +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.ptn.sa-contentprocessing.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. +var replicaRegionPairs = { + australiaeast: 'australiasoutheast' + centralus: 'westus' + eastasia: 'japaneast' + eastus: 'centralus' + eastus2: 'centralus' + japaneast: 'eastasia' + northeurope: 'westeurope' + southeastasia: 'eastasia' + uksouth: 'westeurope' + westeurope: 'northeurope' +} +var replicaLocation = replicaRegionPairs[?location] + +// ========== Virtual Network ========== // +module virtualNetwork './modules/networking/virtual-network.bicep' = if (enablePrivateNetworking) { + name: take('module.virtual-network.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + addressPrefixes: ['10.0.0.0/8'] + location: location + tags: tags + logAnalyticsWorkspaceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + resourceSuffix: solutionSuffix + enableTelemetry: enableTelemetry + } +} + +// Azure Bastion Host +var bastionHostName = 'bas-${solutionSuffix}' +module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePrivateNetworking) { + name: take('avm.res.network.bastion-host.${bastionHostName}', 64) + params: { + name: bastionHostName + skuName: 'Standard' + location: location + virtualNetworkResourceId: virtualNetwork!.outputs.resourceId + diagnosticSettings: enableMonitoring + ? [ + { + name: 'bastionDiagnostics' + workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + } + ] + : null + tags: tags + enableTelemetry: enableTelemetry + publicIPAddressObject: { + name: 'pip-${bastionHostName}' + } + } +} + +// ========== VM Maintenance Configuration Mapping ========== // + +// Jumpbox Virtual Machine +var jumpboxVmName = take('vm-${solutionSuffix}', 15) +module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enablePrivateNetworking) { + name: take('avm.res.compute.virtual-machine.${jumpboxVmName}', 64) + params: { + name: jumpboxVmName + location: location + tags: tags + enableTelemetry: enableTelemetry + computerName: take(jumpboxVmName, 15) + osType: 'Windows' + vmSize: empty(vmSize) ? 'Standard_D2s_v5' : vmSize + adminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername + adminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword + managedIdentities: { + systemAssigned: true + } + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId + enableAutomaticUpdates: true + encryptionAtHost: false + availabilityZone: enableRedundancy ? 1 : -1 + imageReference: { + publisher: 'microsoft-dsvm' + offer: 'dsvm-win-2022' + sku: 'winserver-2022' + version: 'latest' + } + osDisk: { + name: 'osdisk-${jumpboxVmName}' + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + // WAF aligned configuration - use Premium storage for better SLA when redundancy is enabled + storageAccountType: enableRedundancy ? 'Premium_LRS' : 'Standard_LRS' + } + } + nicConfigurations: [ + { + name: 'nic-${jumpboxVmName}' + tags: tags + deleteOption: 'Delete' + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : null + ipConfigurations: [ + { + name: '${jumpboxVmName}-nic01-ipconfig01' + subnetResourceId: virtualNetwork!.outputs.administrationSubnetResourceId + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : null + } + ] + } + ] + extensionAadJoinConfig: { + enabled: true + tags: tags + typeHandlerVersion: '1.0' + settings: { + mdmId:'' + } + } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: tags + } + //WAF aligned configuration for Monitoring + extensionMonitoringAgentConfig: enableMonitoring + ? { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId + name: 'send-${logAnalyticsWorkspace!.outputs.name}' + } + ] + enabled: true + tags: tags + } + : null + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: tags + } + } +} + +module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = if (enablePrivateNetworking) { + name: take('avm.res.maintenance-configuration.${jumpboxVmName}', 64) + params: { + name: 'mc-${jumpboxVmName}' + location: location + tags: tags + enableTelemetry: enableTelemetry + extensionProperties: { + InGuestPatchMode: 'User' + } + maintenanceScope: 'InGuestPatch' + maintenanceWindow: { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' + } + visibility: 'Custom' + installPatches: { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + } + } +} + +var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' +var dataCollectionRulesLocation = logAnalyticsWorkspace!.outputs.location +var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' +var dcrLogAnalyticsDestinationName = 'la-${logAnalyticsWorkspaceResourceName}-destination' +module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.11.0' = if (enablePrivateNetworking && enableMonitoring) { + name: take('avm.res.insights.data-collection-rule.${dataCollectionRulesResourceName}', 64) + params: { + name: dataCollectionRulesResourceName + tags: tags + enableTelemetry: enableTelemetry + location: dataCollectionRulesLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + performanceCounters: [ + { + streams: [ + 'Microsoft-Perf' + ] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' + } + ] + windowsEventLogs: [ + { + name: 'SecurityAuditEvents' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' + ] + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId + name: dcrLogAnalyticsDestinationName + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + { + streams: [ + 'Microsoft-Event' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + transformKql: 'source' + outputStream: 'Microsoft-Event' + } + ] + } + } +} + +// ========== Private DNS Zones ========== // +var privateDnsZones = [ + 'privatelink.cognitiveservices.azure.com' + 'privatelink.openai.azure.com' + 'privatelink.services.ai.azure.com' + 'privatelink.contentunderstanding.ai.azure.com' + 'privatelink.blob.${environment().suffixes.storage}' + 'privatelink.queue.${environment().suffixes.storage}' + 'privatelink.mongo.cosmos.azure.com' + 'privatelink.azconfig.io' + 'privatelink.azurecr.io' +] + +// DNS Zone Index Constants +var dnsZoneIndex = { + cognitiveServices: 0 + openAI: 1 + aiServices: 2 + contentUnderstanding: 3 + storageBlob: 4 + storageQueue: 5 + cosmosDB: 6 + appConfig: 7 + containerRegistry: 8 +} + +@batchSize(5) +module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ + for (zone, i) in privateDnsZones: if (enablePrivateNetworking) { + name: take('avm.res.network.private-dns-zone.${split(zone, '.')[1]}', 64) + params: { + name: zone + tags: tags + enableTelemetry: enableTelemetry + virtualNetworkLinks: [{ virtualNetworkResourceId: virtualNetwork!.outputs.resourceId }] + } + } +] + +// ========== Log Analytics & Application Insights ========== // +module logAnalyticsWorkspace './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { + name: take('module.log-analytics-workspace.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: logAnalyticsWorkspaceResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + enableReplication: enableRedundancy + replicationLocation: replicaLocation + } +} + +module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (enableMonitoring) { + name: take('avm.res.insights.component.${solutionSuffix}', 64) + params: { + name: 'appi-${solutionSuffix}' + location: location + enableTelemetry: enableTelemetry + retentionInDays: 365 + kind: 'web' + disableIpMasking: false + flowType: 'Bluefield' + // WAF aligned configuration for Monitoring + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null + tags: tags + } +} + +@description('Optional. Tag, Created by user name.') +param createdBy string = contains(deployer(), 'userPrincipalName') + ? split(deployer().userPrincipalName, '@')[0] + : deployer().objectId + +// ========== Resource Group Tag ========== // +resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { + name: 'default' + properties: { + tags: { + ...resourceGroup().tags + ...tags + TemplateName: 'Content Processing' + Type: enablePrivateNetworking ? 'WAF' : 'Non-WAF' + CreatedBy: createdBy + DeploymentName: deployment().name + } + } +} + +// ========== Managed Identity ========== // +module avmManagedIdentity './modules/identity/managed-identity.bicep' = { + name: take('module.managed-identity.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + identityName: 'id-${solutionSuffix}' + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +module avmContainerRegistry './modules/compute/container-registry.bicep' = { + name: take('module.container-registry.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: 'cr${replace(solutionSuffix, '-', '')}' + location: location + sku: enableRedundancy || enablePrivateNetworking ? 'Premium' : 'Standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + acrPullPrincipalIds: [ + avmContainerRegistryReader.outputs.principalId + ] + tags: tags + enableTelemetry: enableTelemetry + enablePrivateNetworking: enablePrivateNetworking + privateEndpointSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.backendSubnetResourceId : '' + privateDnsZoneResourceIds: enablePrivateNetworking + ? [avmPrivateDnsZones[dnsZoneIndex.containerRegistry]!.outputs.resourceId] + : [] + } +} + +// // ========== Storage Account ========== // +module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { + name: take('module.storage-account.${solutionSuffix}', 64) + params: { + name: 'st${replace(solutionSuffix, '-', '')}' + location: location + managedIdentities: { systemAssigned: true } + minimumTlsVersion: 'TLS1_2' + enableTelemetry: enableTelemetry + roleAssignments: [ + { + principalId: avmManagedIdentity.outputs.principalId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' + ipRules: [] + } + requireInfrastructureEncryption: true + supportsHttpsTrafficOnly: true + accessTier: 'Hot' + tags: tags + + //<======================= WAF related parameters + allowBlobPublicAccess: false + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + privateEndpoints: (enablePrivateNetworking) + ? [ + { + name: 'pep-blob-${solutionSuffix}' + customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'storage-dns-zone-group-blob' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + service: 'blob' + } + { + name: 'pep-queue-${solutionSuffix}' + customNetworkInterfaceName: 'nic-queue-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'storage-dns-zone-group-queue' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageQueue]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + service: 'queue' + } + ] + : [] + } +} + +// // ========== AI Foundry and related resources ========== // +module avmAiServices './modules/ai/ai-foundry.bicep' = { + name: take('module.ai-services.${solutionSuffix}', 64) + params: { + name: 'aif-${solutionSuffix}' + projectName: 'proj-${solutionSuffix}' + projectDescription: 'proj-${solutionSuffix}' + existingFoundryProjectResourceId: existingProjectResourceId + location: azureAiServiceLocation + sku: 'S0' + allowProjectManagement: true + managedIdentities: { systemAssigned: true } + kind: 'AIServices' + tags: { + app: solutionSuffix + location: azureAiServiceLocation + } + customSubDomainName: 'aif-${solutionSuffix}' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null + roleAssignments: [ + { + principalId: avmManagedIdentity.outputs.principalId + roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' + } + disableLocalAuth: true + enableTelemetry: enableTelemetry + deployments: [ + { + name: gptModelName + model: { + format: 'OpenAI' + name: gptModelName + version: gptModelVersion + } + sku: { + name: deploymentType + capacity: gptDeploymentCapacity + } + raiPolicyName: 'Microsoft.Default' + } + ] + + // WAF related parameters + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + //publicNetworkAccess: 'Enabled' // Always enabled for AI Services + } +} + +module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking && empty(existingProjectResourceId)) { + name: take('avm.res.network.private-endpoint.${solutionSuffix}', 64) + params: { + name: 'pep-aiservices-${solutionSuffix}' + location: location + tags: tags + customNetworkInterfaceName: 'nic-aiservices-${solutionSuffix}' + privateLinkServiceConnections: [ + { + name: 'pep-aiservices-${solutionSuffix}-cognitiveservices-connection' + properties: { + privateLinkServiceId: avmAiServices.outputs.resourceId + groupIds: ['account'] + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'ai-services-dns-zone-cognitiveservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-openai' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-aiservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-contentunderstanding' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId + } +} + +// ========== Container App Environment ========== // +module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { + name: take('avm.res.app.managed-environment.${solutionSuffix}', 64) + params: { + name: 'cae-${solutionSuffix}' + location: location + tags: { + ...resourceGroup().tags + ...tags + } + managedIdentities: { systemAssigned: true } + appLogsConfiguration: enableMonitoring + ? { + destination: 'log-analytics' + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId + } + : null + workloadProfiles: [ + { + name: 'Consumption' + workloadProfileType: 'Consumption' + } + ] + enableTelemetry: enableTelemetry + publicNetworkAccess: 'Enabled' // Always enabled for Container Apps Environment + + // <========== WAF related parameters + + platformReservedCidr: '172.17.17.0/24' + platformReservedDnsIP: '172.17.17.17' + zoneRedundant: (enablePrivateNetworking) ? true : false // Enable zone redundancy if private networking is enabled + infrastructureSubnetResourceId: (enablePrivateNetworking) + ? virtualNetwork!.outputs.webserverfarmSubnetResourceId // Use the container app subnet + : null // Use the container app subnet + } +} + +// //=========== Managed Identity for Container Registry ========== // +module avmContainerRegistryReader 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { + name: take('avm.res.managed-identity.user-assigned-identity.${solutionSuffix}', 64) + params: { + name: 'id-acr-${solutionSuffix}' + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ========== Container App ========== // +module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-app' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + + containers: [ + { + name: 'ca-${solutionSuffix}' + image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' + + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: '' + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + tags: tags + } +} + +// ========== Container App API ========== // +module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-api.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-api' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-api' + image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: '' + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ] + probes: [ + // Liveness Probe - Checks if the app is still running + { + type: 'Liveness' + httpGet: { + path: '/startup' // Your app must expose this endpoint + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + // Readiness Probe - Checks if the app is ready to receive traffic + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 // Wait 10s before checking + periodSeconds: 5 // Check every 15s + failureThreshold: 10 // Restart if it fails 5 times + } + ] + } + ] + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] + } + ingressExternal: true + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + corsPolicy: { + allowedOrigins: [ + '*' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + 'Authorization' + 'Content-Type' + '*' + ] + } + } +} + +//========== Container App Web ========== // +module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-web.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-web' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + ingressExternal: true + ingressTargetPort: 3000 + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-web' + image: '${containerRegistryEndpoint}/contentprocessorweb:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_API_BASE_URL' + value: 'https://${avmContainerApp_API.outputs.fqdn}' + } + { + name: 'APP_WEB_CLIENT_ID' + value: '' + } + { + name: 'APP_WEB_AUTHORITY' + value: '${environment().authentication.loginEndpoint}/${tenant().tenantId}' + } + { + name: 'APP_WEB_SCOPE' + value: '' + } + { + name: 'APP_API_SCOPE' + value: '' + } + { + name: 'APP_REDIRECT_URL' + value: '/' + } + { + name: 'APP_POST_REDIRECT_URL' + value: '/' + } + { + name: 'APP_CONSOLE_LOG_ENABLED' + value: 'false' + } + ] + } + ] + } +} + +// ========== Container App Workflow ========== // +module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-wkfl.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-wkfl' + location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-wkfl' + image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: '' + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + } +} + +// ========== Cosmos Database for Mongo DB ========== // +module avmCosmosDB 'br/public:avm/res/document-db/database-account:0.19.0' = { + name: take('avm.res.document-db.database-account.${solutionSuffix}', 64) + params: { + name: 'cosmos-${solutionSuffix}' + location: location + mongodbDatabases: [ + { + name: 'default' + tag: 'default database' + } + ] + tags: tags + enableTelemetry: enableTelemetry + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + serverVersion: '7.0' + capabilitiesToAdd: [ + 'EnableMongo' + ] + defaultConsistencyLevel: 'Session' + maxIntervalInSeconds: 5 + maxStalenessPrefix: 100 + zoneRedundant: false + + // WAF related parameters + networkRestrictions: { + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + ipRules: [] + virtualNetworkRules: [] + } + + privateEndpoints: (enablePrivateNetworking) + ? [ + { + name: 'pep-cosmosdb-${solutionSuffix}' + customNetworkInterfaceName: 'nic-cosmosdb-${solutionSuffix}' + privateEndpointResourceId: virtualNetwork!.outputs.resourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'cosmosdb-dns-zone-group' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId + } + ] + } + service: 'MongoDB' + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + } + ] + : [] + } +} + +// ========== AI Search ========== // +module avmAiSearch './modules/ai/ai-search.bicep' = { + name: take('module.ai-search.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: 'srch-${solutionSuffix}' + location: location + skuName: 'basic' + replicaCount: enableRedundancy ? 2 : 1 + partitionCount: enableScalability ? 2 : 1 + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ========== App Configuration ========== // +module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { + name: take('avm.res.app.configuration-store.${solutionSuffix}', 64) + params: { + name: 'appcs-${solutionSuffix}' + location: location + enablePurgeProtection: enablePurgeProtection + tags: { + app: solutionSuffix + location: location + } + enableTelemetry: enableTelemetry + managedIdentities: { systemAssigned: true } + sku: 'Standard' + diagnosticSettings: enableMonitoring + ? [ + { + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + } + ] + : null + disableLocalAuth: false + replicaLocations: enableRedundancy? [{ replicaLocation: replicaLocation }] : [] + roleAssignments: [ + { + principalId: avmContainerApp.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_API.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Web.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + ] + keyValues: [ + { + name: 'APP_AZURE_OPENAI_ENDPOINT' + value: avmAiServices.outputs.endpoint //TODO: replace with actual endpoint + } + { + name: 'APP_AZURE_OPENAI_MODEL' + value: gptModelName + } + { + name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + { + name: 'APP_COSMOS_CONTAINER_PROCESS' + value: 'Processes' + } + { + name: 'APP_COSMOS_CONTAINER_SCHEMA' + value: 'Schemas' + } + { + name: 'APP_COSMOS_DATABASE' + value: 'ContentProcess' + } + { + name: 'APP_CPS_CONFIGURATION' + value: 'cps-configuration' + } + { + name: 'APP_CPS_MAX_FILESIZE_MB' + value: '20' + } + { + name: 'APP_CPS_PROCESSES' + value: 'cps-processes' + } + { + name: 'APP_MESSAGE_QUEUE_EXTRACT' + value: 'content-pipeline-extract-queue' + } + { + name: 'APP_MESSAGE_QUEUE_INTERVAL' + value: '5' + } + { + name: 'APP_MESSAGE_QUEUE_PROCESS_TIMEOUT' + value: '180' + } + { + name: 'APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT' + value: '10' + } + { + name: 'APP_PROCESS_STEPS' + value: 'extract,map,evaluate,save' + } + { + name: 'APP_STORAGE_BLOB_URL' + value: avmStorageAccount.outputs.serviceEndpoints.blob + } + { + name: 'APP_STORAGE_QUEUE_URL' + value: avmStorageAccount.outputs.serviceEndpoints.queue + } + { + name: 'APP_AI_PROJECT_ENDPOINT' + value: avmAiServices.outputs.aiProjectInfo.?apiEndpoint ?? '' + } + { + name: 'APP_COSMOS_CONNSTR' + value: avmCosmosDB.outputs.primaryReadWriteConnectionString + } + // ===== v2 Workflow Keys ===== // + { + name: 'APP_COSMOS_CONTAINER_BATCH_PROCESS' + value: 'claimprocesses' + } + { + name: 'APP_COSMOS_CONTAINER_BATCHES' + value: 'batches' + } + { + name: 'APP_COSMOS_CONTAINER_SCHEMASET' + value: 'Schemasets' + } + { + name: 'APP_CPS_PROCESS_BATCH' + value: 'process-batch' + } + { + name: 'APP_CPS_CONTENT_PROCESS_ENDPOINT' + value: 'http://${avmContainerApp_API.outputs.name}/' + } + { + name: 'APP_CPS_POLL_INTERVAL_SECONDS' + value: '3' + } + { + name: 'APP_STORAGE_ACCOUNT_NAME' + value: avmStorageAccount.outputs.name + } + { + name: 'CLAIM_PROCESS_QUEUE_NAME' + value: 'claim-process-queue' + } + { + name: 'DEAD_LETTER_QUEUE_NAME' + value: 'claim-process-dead-letter-queue' + } + { + name: 'AZURE_OPENAI_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + { + name: 'AZURE_OPENAI_CHAT_DEPLOYMENT_NAME' + value: gptModelName + } + { + name: 'AZURE_OPENAI_API_VERSION' + value: '2025-03-01-preview' + } + { + name: 'AZURE_OPENAI_ENDPOINT_BASE' + value: avmAiServices.outputs.endpoint + } + // ===== Agent Framework Keys ===== // + { + name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' + value: '' + } + { + name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' + value: '' + } + { + name: 'AZURE_TRACING_ENABLED' + value: 'True' + } + { + name: 'GLOBAL_LLM_SERVICE' + value: 'AzureOpenAI' + } + // ===== GPT-5 Service Prefix Keys ===== // + { + name: 'GPT5_API_VERSION' + value: '2025-03-01-preview' + } + { + name: 'GPT5_CHAT_DEPLOYMENT_NAME' + value: 'gpt-5' + } + { + name: 'GPT5_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + // ===== PHI-4 Service Prefix Keys ===== // + { + name: 'PHI4_API_VERSION' + value: '2024-05-01-preview' + } + { + name: 'PHI4_CHAT_DEPLOYMENT_NAME' + value: 'phi-4' + } + { + name: 'PHI4_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + ] + + publicNetworkAccess: 'Enabled' + } +} + +module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = if (enablePrivateNetworking) { + name: take('avm.res.app.configuration-store.update.${solutionSuffix}', 64) + params: { + name: 'appcs-${solutionSuffix}' + location: location + enablePurgeProtection: enablePurgeProtection + enableTelemetry: enableTelemetry + tags: tags + publicNetworkAccess: 'Disabled' + privateEndpoints: [ + { + name: 'pep-appconfig-${solutionSuffix}' + customNetworkInterfaceName: 'nic-appconfig-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'appconfig-dns-zone-group' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.appConfig]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + } + ] + } + + dependsOn: [ + avmAppConfig + ] +} + +// ========== Container App Update Modules ========== // +module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-update.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-app' + location: location + enableTelemetry: enableTelemetry + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}' + image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' + + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: enableScalability + ? [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: 100 + } + } + } + ] + : [] + } + } + dependsOn: [ + cognitiveServicePrivateEndpoint + ] +} + +module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-api' + location: location + enableTelemetry: enableTelemetry + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + + containers: [ + { + name: 'ca-${solutionSuffix}-api' + image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ] + probes: [ + // Liveness Probe - Checks if the app is still running + { + type: 'Liveness' + httpGet: { + path: '/startup' // Your app must expose this endpoint + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + // Readiness Probe - Checks if the app is ready to receive traffic + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 // Wait 10s before checking + periodSeconds: 5 // Check every 15s + failureThreshold: 10 // Restart if it fails 5 times + } + ] + } + ] + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] + } + ingressExternal: true + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + corsPolicy: { + allowedOrigins: [ + '*' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + 'Authorization' + 'Content-Type' + '*' + ] + } + } + dependsOn: [ + cognitiveServicePrivateEndpoint + ] +} + +// ========== Container App Workflow Update ========== // +module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-wkfl' + location: location + enableTelemetry: enableTelemetry + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ + { + name: 'ca-${solutionSuffix}-wkfl' + image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The name of the Container App used for Web App.') +output CONTAINER_WEB_APP_NAME string = avmContainerApp_Web.outputs.name + +@description('The name of the Container App used for API.') +output CONTAINER_API_APP_NAME string = avmContainerApp_API.outputs.name + +@description('The FQDN of the Container App.') +output CONTAINER_WEB_APP_FQDN string = avmContainerApp_Web.outputs.fqdn + +@description('The FQDN of the Container App API.') +output CONTAINER_API_APP_FQDN string = avmContainerApp_API.outputs.fqdn + +@description('The name of the Container App used for APP.') +output CONTAINER_APP_NAME string = avmContainerApp.outputs.name + +@description('The name of the Container App used for Workflow.') +output CONTAINER_WORKFLOW_APP_NAME string = avmContainerApp_Workflow.outputs.name + +@description('The user identity resource ID used fot the Container APP.') +output CONTAINER_APP_USER_IDENTITY_ID string = avmContainerRegistryReader.outputs.resourceId + +@description('The user identity Principal ID used fot the Container APP.') +output CONTAINER_APP_USER_PRINCIPAL_ID string = avmContainerRegistryReader.outputs.principalId + +@description('The name of the Azure Container Registry.') +output CONTAINER_REGISTRY_NAME string = avmContainerRegistry.outputs.name + +@description('The login server of the Azure Container Registry.') +output CONTAINER_REGISTRY_LOGIN_SERVER string = avmContainerRegistry.outputs.loginServer + +@description('The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA.') +output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices.outputs.name + +@description('The resource group the resources were deployed into.') +output AZURE_RESOURCE_GROUP string = resourceGroup().name + +@description('The solution name.') +output SOLUTION_NAME string = solutionName diff --git a/infra/avm/main.json b/infra/avm/main.json new file mode 100644 index 00000000..eabf3776 --- /dev/null +++ b/infra/avm/main.json @@ -0,0 +1,68661 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17324347463484125167" + }, + "name": "Content Processing Solution Accelerator", + "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." + }, + "parameters": { + "solutionName": { + "type": "string", + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20, + "metadata": { + "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." + } + }, + "location": { + "type": "string", + "allowedValues": [ + "australiaeast", + "centralus", + "eastasia", + "eastus2", + "japaneast", + "northeurope", + "southeastasia", + "uksouth" + ], + "metadata": { + "azd": { + "type": "location" + }, + "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." + } + }, + "azureAiServiceLocation": { + "type": "string", + "allowedValues": [ + "australiaeast", + "eastus", + "eastus2", + "japaneast", + "southcentralus", + "southeastasia", + "swedencentral", + "uksouth", + "westeurope", + "westus", + "westus3" + ], + "metadata": { + "azd": { + "type": "location", + "usageName": [ + "OpenAI.GlobalStandard.gpt-5.1,300" + ] + }, + "description": "Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead." + }, + "minLength": 1 + }, + "deploymentType": { + "type": "string", + "defaultValue": "GlobalStandard", + "allowedValues": [ + "Standard", + "GlobalStandard" + ], + "minLength": 1, + "metadata": { + "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." + } + }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1", + "metadata": { + "description": "Optional. Name of the GPT model to deploy: gpt-5.1" + } + }, + "gptModelVersion": { + "type": "string", + "defaultValue": "2025-11-13", + "allowedValues": [ + "2025-11-13" + ], + "minLength": 1, + "metadata": { + "description": "Optional. Version of the GPT model to deploy:." + } + }, + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": 300, + "minValue": 1, + "metadata": { + "description": "Optional. Capacity of the GPT deployment: (minimum 10)." + } + }, + "containerRegistryEndpoint": { + "type": "string", + "defaultValue": "cpscontainerreg.azurecr.io", + "metadata": { + "description": "Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint)." + } + }, + "imageTag": { + "type": "string", + "defaultValue": "latest_v2", + "metadata": { + "description": "Optional. The image tag for the container images." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable WAF for the deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + } + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enableScalability": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable purge protection. Defaults to false." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" + }, + "description": "Optional. Tags to be applied to the resources." + }, + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + } + }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Existing Log Analytics Workspace Resource ID" + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Use this parameter to use an existing AI project resource ID" + } + }, + "vmSize": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminUsername": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." + } + }, + "createdBy": { + "type": "string", + "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", + "metadata": { + "description": "Optional. Tag, Created by user name." + } + } + }, + "variables": { + "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", + "existingProjectResourceId": "[trim(parameters('existingFoundryProjectResourceId'))]", + "replicaRegionPairs": { + "australiaeast": "australiasoutheast", + "centralus": "westus", + "eastasia": "japaneast", + "eastus": "centralus", + "eastus2": "centralus", + "japaneast": "eastasia", + "northeurope": "westeurope", + "southeastasia": "eastasia", + "uksouth": "westeurope", + "westeurope": "northeurope" + }, + "replicaLocation": "[tryGet(variables('replicaRegionPairs'), parameters('location'))]", + "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", + "jumpboxVmName": "[take(format('vm-{0}', variables('solutionSuffix')), 15)]", + "dataCollectionRulesResourceName": "[format('dcr-{0}', variables('solutionSuffix'))]", + "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", + "dcrLogAnalyticsDestinationName": "[format('la-{0}-destination', variables('logAnalyticsWorkspaceResourceName'))]", + "privateDnsZones": [ + "privatelink.cognitiveservices.azure.com", + "privatelink.openai.azure.com", + "privatelink.services.ai.azure.com", + "privatelink.contentunderstanding.ai.azure.com", + "[format('privatelink.blob.{0}', environment().suffixes.storage)]", + "[format('privatelink.queue.{0}', environment().suffixes.storage)]", + "privatelink.mongo.cosmos.azure.com", + "privatelink.azconfig.io", + "privatelink.azurecr.io" + ], + "dnsZoneIndex": { + "cognitiveServices": 0, + "openAI": 1, + "aiServices": 2, + "contentUnderstanding": 3, + "storageBlob": 4, + "storageQueue": 5, + "cosmosDB": 6, + "appConfig": 7, + "containerRegistry": 8 + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('46d3xbcp.ptn.sa-contentprocessing.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroupTags": { + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", + "properties": { + "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" + } + }, + "virtualNetwork": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "addressPrefixes": { + "value": [ + "10.0.0.0/8" + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "resourceSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "10323079586505814920" + } + }, + "definitions": { + "subnetOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the subnet." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the subnet." + } + }, + "nsgName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The name of the associated NSG, if any." + } + }, + "nsgResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The resource ID of the associated NSG, if any." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Subnet output type" + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. Address prefixes for the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Delegation for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Private endpoint network policies." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Private link service network policies." + } + }, + "networkSecurityGroup": { + "$ref": "#/definitions/networkSecurityGroupType", + "nullable": true, + "metadata": { + "description": "Optional. NSG configuration for the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Route table resource ID." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Service endpoints to enable." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable default outbound connectivity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Subnet configuration type" + } + }, + "networkSecurityGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NSG." + } + }, + "securityRules": { + "type": "array", + "items": { + "type": "object" + }, + "metadata": { + "description": "Required. Security rules for the NSG." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "NSG configuration type" + } + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Azure region for the resource." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Address prefixes for the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "defaultValue": [ + { + "name": "backend", + "addressPrefixes": [ + "10.0.0.0/27" + ], + "networkSecurityGroup": { + "name": "nsg-backend", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "webserverfarm", + "addressPrefixes": [ + "10.0.4.0/27" + ], + "delegation": "Microsoft.Web/serverfarms", + "privateEndpointNetworkPolicies": "Enabled", + "privateLinkServiceNetworkPolicies": "Enabled", + "networkSecurityGroup": { + "name": "nsg-webserverfarm", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "administration", + "addressPrefixes": [ + "10.0.0.32/27" + ], + "networkSecurityGroup": { + "name": "nsg-administration", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "AzureBastionSubnet", + "addressPrefixes": [ + "10.0.0.64/26" + ], + "networkSecurityGroup": { + "name": "nsg-bastion", + "securityRules": [ + { + "name": "AllowGatewayManager", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2702, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "GatewayManager", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowHttpsInBound", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2703, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowSshRdpOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 100, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AllowAzureCloudOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 110, + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "AzureCloud" + } + } + ] + } + } + ], + "metadata": { + "description": "Subnet configurations." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resources." + } + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics Workspace for diagnostics." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceSuffix": { + "type": "string", + "metadata": { + "description": "Suffix for resource naming." + } + } + }, + "variables": { + "name": "[format('vnet-{0}', parameters('solutionName'))]" + }, + "resources": { + "nsgs": { + "copy": { + "name": "nsgs", + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "securityRules": { + "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7311263652424030280" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG)." + }, + "definitions": { + "securityRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "properties": { + "type": "object", + "properties": { + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the security rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 4096, + "metadata": { + "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "metadata": { + "description": "Required. The properties of the security rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a security rule." + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "securityRules": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" + }, + "description": "Optional. Tags of the NSG resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(coalesce(parameters('securityRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "properties": { + "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", + "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", + "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", + "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", + "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", + "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", + "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", + "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", + "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", + "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", + "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", + "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", + "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", + "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", + "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { + "copy": { + "name": "networkSecurityGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "addressPrefixes": { + "value": "[parameters('addressPrefixes')]" + }, + "subnets": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('subnets'))]", + "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "name": "vnetDiagnostics", + "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs", + "enabled": true + } + ], + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11272001757446231867" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet)." + }, + "definitions": { + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "prefixItems": [ + { + "type": "object", + "properties": { + "pool": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + } + }, + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + }, + "numberOfIpAddresses": { + "type": "string", + "metadata": { + "description": "Required. Number of IP addresses allocated from the pool." + } + } + } + } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." + } + }, + "ipamPoolNumberOfIpAddresses": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + }, + "enablePrivateEndpointVNetPolicies": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Basic", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]", + "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "ipamPoolPrefixAllocations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13992200806189615656" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + } + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "metadata": { + "description": "The IPAM pool prefix allocations for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "nsgs" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.name.value]" + }, + "resourceId": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetOutputType" + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex()].name]", + "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", + "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", + "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" + } + } + }, + "backendSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" + }, + "webserverfarmSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" + }, + "administrationSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" + }, + "bastionSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "bastionHost": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('bastionHostName')]" + }, + "skuName": { + "value": "Standard" + }, + "location": { + "value": "[parameters('location')]" + }, + "virtualNetworkResourceId": { + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": { + "name": "[format('pip-{0}', variables('bastionHostName'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7741601918225805390" + }, + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host." + }, + "definitions": { + "publicIPAddressObjectType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for the Public IP resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create for the Public IP resource." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the Public IP module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Idle timeout in minutes for the Public IP resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to apply to the Public IP resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the Public IP resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Bastion resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Shared services Virtual Network resource Id." + } + }, + "bastionSubnetPublicIpResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "publicIPAddressObject": { + "$ref": "#/definitions/publicIPAddressObjectType", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Developer", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. The SKU of this Bastion Host." + } + }, + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." + } + }, + "enableFileCopy": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." + } + }, + "enableIpConnect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." + } + }, + "enableKerberos": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." + } + }, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." + } + }, + "enableSessionRecording": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." + } + }, + "enablePrivateOnlyBastion": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." + } + }, + "scaleUnits": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. The list of Availability zones to use for the zone-redundant resources." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[coalesce(parameters('tags'), createObject())]", + "sku": { + "name": "[parameters('skuName')]" + }, + "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", + "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] + }, + "azureBastion_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_diagnosticSettings": { + "copy": { + "name": "azureBastion_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "publicIPAddress": { + "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" + }, + "ipTags": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "16564959277054027786" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "deleteOption": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Delete", + "Detach" + ], + "metadata": { + "description": "Optional. The delete option for the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure Bastion was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name the Azure Bastion." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID the Azure Bastion." + }, + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureBastion', '2025-01-01', 'full').location]" + }, + "ipConfAzureBastionSubnet": { + "type": "object", + "metadata": { + "description": "The Public IPconfiguration object for the AzureBastionSubnet." + }, + "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "virtualNetwork" + ] + }, + "jumpboxVM": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('jumpboxVmName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "computerName": { + "value": "[take(variables('jumpboxVmName'), 15)]" + }, + "osType": { + "value": "Windows" + }, + "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", + "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", + "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": true + }, + "maintenanceConfigurationResourceId": { + "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", + "imageReference": { + "value": { + "publisher": "microsoft-dsvm", + "offer": "dsvm-win-2022", + "sku": "winserver-2022", + "version": "latest" + } + }, + "osDisk": { + "value": { + "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" + } + } + }, + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-{0}', variables('jumpboxVmName'))]", + "tags": "[parameters('tags')]", + "deleteOption": "Delete", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", + "ipConfigurations": [ + { + "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", + "subnetResourceId": "[reference('virtualNetwork').outputs.administrationSubnetResourceId.value]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" + } + ] + } + ] + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]", + "typeHandlerVersion": "1.0", + "settings": { + "mdmId": "" + } + } + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": {}, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + }, + "tags": "[parameters('tags')]" + } + }, + "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17174537341033050778" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." + }, + "definitions": { + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "diffDiskSettings": { + "type": "object", + "properties": { + "placement": { + "type": "string", + "allowedValues": [ + "CacheDisk", + "NvmeDisk", + "ResourceDisk" + ], + "metadata": { + "description": "Required. Specifies the ephemeral disk placement for the operating system disk." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing an OS disk." + } + }, + "dataDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" + }, + "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a data disk." + } + }, + "publicKeyType": { + "type": "object", + "properties": { + "keyData": { + "type": "string", + "metadata": { + "description": "Required. Specifies the SSH public key data used to authenticate through ssh." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." + } + } + } + }, + "nicConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the NIC configuration." + } + }, + "nicSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The suffix to append to the NIC name." + } + }, + "enableIPForwarding": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify what happens to the network interface when the VM is deleted." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "metadata": { + "description": "Required. The IP configurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the NIC configuration." + } + }, + "imageReferenceType": { + "type": "object", + "properties": { + "communityGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." + } + }, + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource Id of the image reference." + } + }, + "offer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The image publisher." + } + }, + "sku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SKU of the image." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." + } + }, + "sharedGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the image reference." + } + }, + "planType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the plan." + } + }, + "product": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the product of the image from the marketplace." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher ID." + } + }, + "promotionCode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The promotion code." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Specifies information about the marketplace image used to create the virtual machine." + } + }, + "autoShutDownConfigType": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the auto shutdown configuration." + } + }, + "timeZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." + } + }, + "dailyRecurrenceTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time of day the schedule will occur." + } + }, + "notificationSettings": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the notification settings." + } + }, + "emailRecipient": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." + } + }, + "notificationLocale": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + } + }, + "webhookUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The webhook URL to which the notification will be sent." + } + }, + "timeInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The time in minutes before shutdown to send notifications." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the schedule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the configuration profile." + } + }, + "vaultSecretGroupType": { + "type": "object", + "properties": { + "sourceVault": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." + } + }, + "vaultCertificates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "certificateStore": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + } + }, + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of key vault references in SourceVault which contain certificates." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the set of certificates that should be installed onto the virtual machine." + } + }, + "vmGalleryApplicationType": { + "type": "object", + "properties": { + "packageReferenceId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." + } + }, + "configurationReference": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." + } + }, + "order": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the order in which the packages have to be installed." + } + }, + "tags": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies a passthrough value for more generic context." + } + }, + "treatFailureAsDeploymentFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the gallery application that should be made available to the VM/VMSS." + } + }, + "additionalUnattendContentType": { + "type": "object", + "properties": { + "settingName": { + "type": "string", + "allowedValues": [ + "AutoLogon", + "FirstLogonCommands" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the setting to which the content applies." + } + }, + "content": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." + } + }, + "winRMListenerType": { + "type": "object", + "properties": { + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Http", + "Https" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the protocol of WinRM listener." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a Windows Remote Management listener." + } + }, + "nicConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NIC configuration." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "Required. List of IP configurations of the NIC configuration." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the network interface configuration output." + } + }, + "extensionCustomScriptConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." + } + }, + "typeHandlerVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "protectedSettings": { + "type": "secureObject", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." + } + }, + "storageAccountName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." + } + }, + "storageAccountKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The access key of the storage account." + } + }, + "managedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "supressFailures": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a 'CustomScriptExtension' extension." + } + }, + "_1.applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_2.ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_2.dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_2.ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_3.diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_4.publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/_3.lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/_2.ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/_2.dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "description": "The type for the public IP address configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/_4.publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "description": "The type for the IP configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "description": "The type for the network interface IP configuration output.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" + }, + "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." + }, + "nullable": true + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" + }, + "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." + }, + "nullable": true + }, + "plan": { + "$ref": "#/definitions/planType", + "nullable": true, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "type": "array", + "items": { + "$ref": "#/definitions/dataDiskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "hibernationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables hibernation capability on the VM." + } + }, + "adminUsername": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." + } + }, + "userData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "items": { + "$ref": "#/definitions/vaultSecretGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "Deallocate", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "publicKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/publicKeyType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "galleryApplications": { + "type": "array", + "items": { + "$ref": "#/definitions/vmGalleryApplicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." + } + }, + "availabilityZone": { + "type": "int", + "allowedValues": [ + -1, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." + } + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationType" + }, + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Recovery service vault name to add VMs to backup." + } + }, + "backupVaultResourceGroup": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "DefaultPolicy", + "metadata": { + "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + } + }, + "autoShutdownConfig": { + "$ref": "#/definitions/autoShutDownConfigType", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for auto-shutdown." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource Id of a maintenance configuration for this VM." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "dataCollectionRuleAssociations": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "$ref": "#/definitions/extensionCustomScriptConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionHostPoolRegistration": { + "type": "secureObject", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "extensionGuestConfigurationExtension": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "guestConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." + } + }, + "extensionGuestConfigurationExtensionProtectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "disablePasswordAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether password authentication should be disabled." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "enableHotpatching": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "items": { + "$ref": "#/definitions/additionalUnattendContentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRMListeners": { + "type": "array", + "items": { + "$ref": "#/definitions/winRMListenerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + }, + "capacityReservationGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." + } + }, + "networkAccessPolicy": { + "type": "string", + "defaultValue": "DenyAll", + "allowedValues": [ + "AllowAll", + "AllowPrivate", + "DenyAll" + ], + "metadata": { + "description": "Optional. Policy for accessing the disk via network." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Policy for controlling export on the disk." + } + } + }, + "variables": { + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" + } + }, + { + "name": "additionalUnattendContentFormatted", + "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", + "input": { + "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", + "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", + "componentName": "Microsoft-Windows-Shell-Setup", + "passName": "OobeSystem" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", + "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" + }, + "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", + "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "managedDataDisks": { + "copy": { + "name": "managedDataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" + }, + "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", + "type": "Microsoft.Compute/disks", + "apiVersion": "2025-01-02", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", + "location": "[parameters('location')]", + "sku": { + "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" + }, + "properties": { + "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", + "creationData": { + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" + }, + "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", + "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "networkAccessPolicy": "[parameters('networkAccessPolicy')]" + }, + "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", + "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", + "plan": "[parameters('plan')]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", + "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", + "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", + "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", + "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", + "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", + "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", + "osType": "[parameters('osType')]", + "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", + "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", + "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", + "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", + "managedDisk": { + "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", + "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", + "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", + "hibernationEnabled": "[parameters('hibernationEnabled')]" + }, + "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" + } + } + ] + }, + "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", + "licenseType": "[parameters('licenseType')]", + "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" + }, + "dependsOn": [ + "managedDataDisks", + "vm_nic" + ] + }, + "vm_configurationAssignment": { + "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", + "type": "Microsoft.Maintenance/configurationAssignments", + "apiVersion": "2023-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[format('{0}assignment', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", + "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_autoShutdownConfiguration": { + "condition": "[not(empty(parameters('autoShutdownConfig')))]", + "type": "Microsoft.DevTestLab/schedules", + "apiVersion": "2018-09-15", + "name": "[format('shutdown-computevm-{0}', parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", + "properties": { + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", + "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "taskType": "ComputeVmShutdownTask", + "dailyRecurrence": { + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" + }, + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_dataCollectionRuleAssociations": { + "copy": { + "name": "vm_dataCollectionRuleAssociations", + "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" + }, + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2024-03-11", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", + "properties": { + "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "cseIdentity": { + "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", + "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" + }, + "AzureWindowsBaseline": { + "condition": "[not(empty(parameters('guestConfiguration')))]", + "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", + "apiVersion": "2024-04-05", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", + "location": "[parameters('location')]", + "properties": { + "guestConfiguration": "[parameters('guestConfiguration')]" + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + }, + "vm_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_roleAssignments": { + "copy": { + "name": "vm_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" + }, + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" + }, + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" + }, + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "lock": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "5982155361487304817" + } + }, + "definitions": { + "publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the public IP address configuration." + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the IP configuration." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" + }, + "enableTelemetry": { + "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" + }, + "ipTags": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5349747633189946992" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" + }, + "description": "Optional. The public IP address allocation method." + }, + "defaultValue": "Static" + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" + }, + "description": "Optional. IP address version." + }, + "defaultValue": "IPv4" + }, + "dnsSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" + }, + "description": "Optional. The DNS settings of the public IP address." + }, + "nullable": true + }, + "ipTags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" + }, + "description": "Optional. The list of tags associated with the public IP address." + }, + "nullable": true + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" + }, + "description": "Optional. Name of a public IP address SKU." + }, + "defaultValue": "Standard" + }, + "skuTier": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" + }, + "description": "Optional. Tier of a public IP address SKU." + }, + "defaultValue": "Regional" + }, + "ddosSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" + }, + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + }, + "nullable": true + }, + "deleteOption": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" + }, + "description": "Optional. The delete option for the public IP address." + }, + "nullable": true + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "272838238520810437" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface." + }, + "definitions": { + "networkInterfaceIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of load balancer backend address pools." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of references of LoadBalancerInboundNatRules." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the IP configuration is included." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Application Gateway Backend Address Pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The reference to gateway load balancer frontend IP." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Virtual Network Taps." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The resource ID of the deployed resource." + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backend address pool." + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application security group." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application gateway backend address pool." + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the sub resource." + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the inbound NAT rule." + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network tap." + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network interface IP configuration output." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationType" + }, + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "publicIp": { + "copy": { + "name": "publicIp", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", + "existing": true, + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", + "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", + "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", + "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", + "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", + "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", + "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", + "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2024-05-01', 'full').location]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "copy": { + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", + "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", + "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" + } + } + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the network interface." + }, + "value": "[reference('networkInterface').outputs.name.value]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "value": "[reference('networkInterface').outputs.ipConfigurations.value]" + } + } + } + } + }, + "vm_domainJoinExtension": { + "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_domainJoinExtension" + ] + }, + "vm_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] + }, + "vm_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_microsoftAntiMalwareExtension" + ] + }, + "vm_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, + "settings": { + "value": { + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "vm_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_dependencyAgentExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_networkWatcherAgentExtension" + ] + }, + "vm_customScriptExtension": { + "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" + }, + "provisionAfterExtensions": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettingsFromKeyVault": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" + }, + "settings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" + }, + "protectedSettings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "cseIdentity", + "vm" + ] + }, + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_customScriptExtension" + ] + }, + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] + }, + "vm_hostPoolRegistrationExtension": { + "condition": "[parameters('extensionHostPoolRegistration').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.PowerShell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", + "properties": { + "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", + "aadJoin": true + } + } + }, + "protectedSettings": { + "value": { + "properties": { + "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" + } + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_nvidiaGpuDriverWindowsExtension" + ] + }, + "vm_azureGuestConfigurationExtension": { + "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.GuestConfiguration" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, + "protectedSettings": { + "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_hostPoolRegistrationExtension" + ] + }, + "vm_backup": { + "condition": "[not(empty(parameters('backupVaultName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('backupVaultResourceGroup')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyId": { + "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + }, + "protectedItemType": { + "value": "Microsoft.Compute/virtualMachines" + }, + "protectionContainerName": { + "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "recoveryVaultName": { + "value": "[parameters('backupVaultName')]" + }, + "sourceResourceId": { + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17448691641471706096" + }, + "name": "Recovery Service Vaults Protection Container Protected Item", + "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "protectionContainerName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + } + }, + "recoveryVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "protectedItemType": { + "type": "string", + "allowedValues": [ + "AzureFileShareProtectedItem", + "AzureVmWorkloadSAPAseDatabase", + "AzureVmWorkloadSAPHanaDatabase", + "AzureVmWorkloadSQLDatabase", + "DPMProtectedItem", + "GenericProtectedItem", + "MabFileFolderProtectedItem", + "Microsoft.ClassicCompute/virtualMachines", + "Microsoft.Compute/virtualMachines", + "Microsoft.Sql/servers/databases" + ], + "metadata": { + "description": "Required. The backup item type." + } + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Required. ID of the backup policy with which this item is backed up." + } + }, + "sourceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource to back up." + } + } + }, + "resources": [ + { + "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", + "apiVersion": "2025-02-01", + "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "protectedItemType": "[parameters('protectedItemType')]", + "policyId": "[parameters('policyId')]", + "sourceResourceId": "[parameters('sourceResourceId')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the protected item was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the protected item." + }, + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The Name of the protected item." + }, + "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VM." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2024-07-01', 'full').location]" + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationOutputType" + }, + "metadata": { + "description": "The list of NIC configurations of the virtual machine." + }, + "copy": { + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", + "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" + } + } + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "maintenanceConfiguration", + "virtualNetwork", + "windowsVmDataCollectionRules" + ] + }, + "maintenanceConfiguration": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('mc-{0}', variables('jumpboxVmName'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionProperties": { + "value": { + "InGuestPatchMode": "User" + } + }, + "maintenanceScope": { + "value": "InGuestPatch" + }, + "maintenanceWindow": { + "value": { + "startDateTime": "2024-06-16 00:00", + "duration": "03:55", + "timeZone": "W. Europe Standard Time", + "recurEvery": "1Day" + } + }, + "visibility": { + "value": "Custom" + }, + "installPatches": { + "value": { + "rebootSetting": "IfRequired", + "windowsParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + }, + "linuxParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + } + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14895287194406877557" + }, + "name": "Maintenance Configurations", + "description": "This module deploys a Maintenance Configuration." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Maintenance Configuration Name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "extensionProperties": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" + }, + "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." + }, + "defaultValue": {} + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "maintenanceScope": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" + }, + "description": "Optional. Gets or sets maintenanceScope of the configuration." + }, + "defaultValue": "Host" + }, + "maintenanceWindow": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" + }, + "description": "Optional. Definition of a MaintenanceWindow." + }, + "defaultValue": {} + }, + "namespace": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Gets or sets namespace of the resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" + }, + "description": "Optional. Gets or sets tags of the resource." + }, + "nullable": true + }, + "visibility": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" + }, + "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." + }, + "nullable": true + }, + "installPatches": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" + }, + "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." + }, + "defaultValue": {} + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "maintenanceConfiguration": { + "type": "Microsoft.Maintenance/maintenanceConfigurations", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "extensionProperties": "[parameters('extensionProperties')]", + "maintenanceScope": "[parameters('maintenanceScope')]", + "maintenanceWindow": "[parameters('maintenanceWindow')]", + "namespace": "[parameters('namespace')]", + "visibility": "[parameters('visibility')]", + "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" + } + }, + "maintenanceConfiguration_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + }, + "maintenanceConfiguration_roleAssignments": { + "copy": { + "name": "maintenanceConfiguration_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Maintenance Configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Maintenance Configuration." + }, + "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Maintenance Configuration was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the Maintenance Configuration was created in." + }, + "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" + } + } + } + } + }, + "windowsVmDataCollectionRules": { + "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('dataCollectionRulesResourceName')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": { + "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" + }, + "dataCollectionRuleProperties": { + "value": { + "kind": "Windows", + "dataSources": { + "performanceCounters": [ + { + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Processes", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Handle Count", + "\\System\\System Up Time", + "\\System\\Context Switches/sec", + "\\System\\Processor Queue Length", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pages/sec", + "\\Memory\\Page Faults/sec", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors" + ], + "name": "perfCounterDataSource60" + } + ], + "windowsEventLogs": [ + { + "name": "SecurityAuditEvents", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" + ] + } + ] + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", + "name": "[variables('dcrLogAnalyticsDestinationName')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Microsoft-Perf" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Perf" + }, + { + "streams": [ + "Microsoft-Event" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Event" + } + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2441324888126124697" + }, + "name": "Data Collection Rules", + "description": "This module deploys a Data Collection Rule." + }, + "definitions": { + "dataCollectionRulePropertiesType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Linux": { + "$ref": "#/definitions/linuxDcrPropertiesType" + }, + "Windows": { + "$ref": "#/definitions/windowsDcrPropertiesType" + }, + "All": { + "$ref": "#/definitions/allPlatformsDcrPropertiesType" + }, + "AgentSettings": { + "$ref": "#/definitions/agentSettingsDcrPropertiesType" + }, + "Direct": { + "$ref": "#/definitions/directDcrPropertiesType" + }, + "WorkspaceTransforms": { + "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" + }, + "PlatformTelemetry": { + "$ref": "#/definitions/platformTelemetryDcrPropertiesType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." + } + }, + "linuxDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Linux" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Linux' data collection rule." + } + }, + "windowsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Windows" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Windows' data collection rule." + } + }, + "allPlatformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the data collection rule of the kind 'All'." + } + }, + "agentSettingsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AgentSettings" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "agentSettings": { + "$ref": "#/definitions/agentSettingsType", + "metadata": { + "description": "Required. Agent settings used to modify agent behavior on a given host." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'AgentSettings' data collection rule." + } + }, + "agentSettingsType": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agentSettingType" + }, + "metadata": { + "description": "Required. All the settings that are applicable to the logs agent (AMA)." + } + } + }, + "metadata": { + "description": "The type for the agent settings." + } + }, + "agentSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "MaxDiskQuotaInMB", + "UseTimeReceivedForForwardedEvents" + ], + "metadata": { + "description": "Required. The name of the agent setting." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the agent setting." + } + } + }, + "metadata": { + "description": "The type for the (single) agent setting." + } + }, + "directDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Direct" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Required. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Direct' data collection rule." + } + }, + "workspaceTransformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "WorkspaceTransforms" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." + } + }, + "platformTelemetryDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "PlatformTelemetry" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "dataSources": { + "type": "object", + "properties": { + "platformTelemetry": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + }, + "description": "Required. The list of platform telemetry configurations." + } + } + }, + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "destinations": { + "type": "object", + "properties": { + "logAnalytics": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + }, + "description": "Optional. The list of Log Analytics destinations." + }, + "nullable": true + }, + "storageAccounts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + }, + "description": "Optional. The list of Storage Account destinations." + }, + "nullable": true + }, + "eventHubs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + }, + "description": "Optional. The list of Event Hub destinations." + }, + "nullable": true + } + }, + "metadata": { + "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the data collection rule. The name is case insensitive." + } + }, + "dataCollectionRuleProperties": { + "$ref": "#/definitions/dataCollectionRulePropertiesType", + "metadata": { + "description": "Required. The kind of data collection rule." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dataCollectionRule": { + "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('dataCollectionRuleProperties').kind]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRuleAll": { + "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRule_conditionalScopeLock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", + "lock": { + "value": "[parameters('lock')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2876136109547890997" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "dataCollectionRuleName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + } + } + }, + "resources": { + "dataCollectionRule": { + "existing": true, + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dataCollectionRuleName')]" + }, + "dataCollectionRule_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + }, + "dataCollectionRule_roleAssignments": { + "copy": { + "name": "dataCollectionRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", + "name": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14634305923902101494" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource." + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dataCollectionRule was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" + }, + "endpoints": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", + "output": true + }, + "description": "The endpoints of the dataCollectionRule, if created." + }, + "nullable": true, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" + }, + "immutableId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The ImmutableId of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "avmPrivateDnsZones": { + "copy": { + "name": "avmPrivateDnsZones", + "count": "[length(variables('privateDnsZones'))]", + "mode": "serial", + "batchSize": 5 + }, + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZones')[copyIndex()]]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "virtualNetworkLinks": { + "value": [ + { + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18337341331267624582" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone." + }, + "definitions": { + "aType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the A record." + } + }, + "aaaaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aaaaRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" + }, + "description": "Optional. The list of AAAA records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the AAAA record." + } + }, + "cnameType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. The CNAME record in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the CNAME record." + } + }, + "mxType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the MX record." + } + }, + "ptrType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the PTR record." + } + }, + "soaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. The SOA record in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SOA record." + } + }, + "srvType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "srvRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SRV record." + } + }, + "txtType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the TXT record." + } + }, + "virtualNetworkLinkType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Optional. The resource name." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the virtual network to link." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Region where the resource lives." + } + }, + "registrationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "resolutionPolicy": { + "type": "string", + "allowedValues": [ + "Default", + "NxDomainRedirect" + ], + "nullable": true, + "metadata": { + "description": "Optional. The resolution type of the private-dns-zone fallback machanism." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network link." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "a": { + "type": "array", + "items": { + "$ref": "#/definitions/aType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of A records." + } + }, + "aaaa": { + "type": "array", + "items": { + "$ref": "#/definitions/aaaaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of AAAA records." + } + }, + "cname": { + "type": "array", + "items": { + "$ref": "#/definitions/cnameType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of CNAME records." + } + }, + "mx": { + "type": "array", + "items": { + "$ref": "#/definitions/mxType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of MX records." + } + }, + "ptr": { + "type": "array", + "items": { + "$ref": "#/definitions/ptrType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of PTR records." + } + }, + "soa": { + "type": "array", + "items": { + "$ref": "#/definitions/soaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SOA records." + } + }, + "srv": { + "type": "array", + "items": { + "$ref": "#/definitions/srvType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SRV records." + } + }, + "txt": { + "type": "array", + "items": { + "$ref": "#/definitions/txtType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of TXT records." + } + }, + "virtualNetworkLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkLinkType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_roleAssignments": { + "copy": { + "name": "privateDnsZone_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_A": { + "copy": { + "name": "privateDnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" + }, + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7372385900111002873" + }, + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the A record." + } + }, + "aRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed A record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed A record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed A record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_AAAA": { + "copy": { + "name": "privateDnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" + }, + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14405855828972373002" + }, + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the AAAA record." + } + }, + "aaaaRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" + }, + "description": "Optional. The list of AAAA records in the record set." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AAAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed AAAA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed AAAA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_CNAME": { + "copy": { + "name": "privateDnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" + }, + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13818627461335065928" + }, + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CNAME record." + } + }, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. A CNAME record." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CNAME record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CNAME record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CNAME record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_MX": { + "copy": { + "name": "privateDnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" + }, + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2977624679479439942" + }, + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_PTR": { + "copy": { + "name": "privateDnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + }, + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15286275176817336979" + }, + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PTR record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SOA": { + "copy": { + "name": "privateDnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" + }, + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4837447718856535826" + }, + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. A SOA record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SRV": { + "copy": { + "name": "privateDnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15028912535488490265" + }, + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "srvRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_TXT": { + "copy": { + "name": "privateDnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" + }, + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7641583415110009849" + }, + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7392770862892927923" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "logAnalyticsWorkspace": { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('logAnalyticsWorkspaceResourceName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableReplication": { + "value": "[parameters('enableRedundancy')]" + }, + "replicationLocation": { + "value": "[variables('replicaLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9919485194443011422" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days. WAF recommends 365." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "metadata": { + "description": "SKU name for the workspace." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access for ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access for query." + } + }, + "enableReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable workspace replication for redundancy." + } + }, + "replicationLocation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Replication location (paired region)." + } + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Data sources for VM monitoring (Windows events, perf counters)." + } + } + }, + "resources": { + "workspace": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": "[parameters('retentionInDays')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "diagnosticSettings": { + "value": [ + { + "useThisWorkspace": true + } + ] + }, + "publicNetworkAccessForIngestion": { + "value": "[parameters('publicNetworkAccessForIngestion')]" + }, + "publicNetworkAccessForQuery": { + "value": "[parameters('publicNetworkAccessForQuery')]" + }, + "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", + "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", + "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14099489006827800075" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace." + }, + "definitions": { + "diagnosticSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "gallerySolutionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the gallery solutions to be created in the log analytics workspace." + } + }, + "storageInsightsConfigType": { + "type": "object", + "properties": { + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the storage account to be linked." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of tables to be read by the workspace." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the storage insights configuration." + } + }, + "linkedServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked service." + } + }, + "linkedStorageAccountType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked storage account." + } + }, + "savedSearchType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "etag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. The category of the saved search. This helps the user to find a saved search faster." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "functionAlias": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. The query expression for the saved search." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The tags attached to the saved search." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language. The current version is 2 and is the default." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the saved search." + } + }, + "dataExportType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data export." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. The destination of the data export." + } + }, + "enable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the data export." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of table names to export." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data export." + } + }, + "dataSourceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "metadata": { + "description": "Required. The kind of data source." + } + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the event log to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data source." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "plan": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The plan for the table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. The restored logs for the table." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. The schema for the table." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. The search results for the table." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The role assignments for the table." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the custom table." + } + }, + "workspaceFeaturesType": { + "type": "object", + "properties": { + "disableLocalAuth": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable Non-EntraID based Auth. Default is true." + } + }, + "enableDataExport": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that indicate if data should be exported." + } + }, + "enableLogAccessUsingOnlyResourcePermissions": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable log access using only resource permissions. Default is false." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that describes if we want to remove the data after 30 days." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Features of the workspace." + } + }, + "workspaceReplicationType": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Replication properties of the workspace." + } + }, + "_1.columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "description": "The parameters of the table column.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "description": "The data export destination properties.", + "__bicep_imported_from!": { + "sourceTemplate": "data-export/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the restore operation that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "description": "The table schema.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the search job that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/storageInsightsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "linkedServices": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedStorageAccountType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + } + }, + "savedSearches": { + "type": "array", + "items": { + "$ref": "#/definitions/savedSearchType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "items": { + "$ref": "#/definitions/dataExportType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "items": { + "$ref": "#/definitions/dataSourceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." + } + }, + "onboardWorkspaceToSentinel": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "-1", + "metadata": { + "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." + } + }, + "defaultDataCollectionRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "features": { + "$ref": "#/definitions/workspaceFeaturesType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace features." + } + }, + "replication": { + "$ref": "#/definitions/workspaceReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace replication properties." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", + "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", + "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", + "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]", + "replication": "[parameters('replication')]", + "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" + }, + "identity": "[variables('identity')]" + }, + "logAnalyticsWorkspace_diagnosticSettings": { + "copy": { + "name": "logAnalyticsWorkspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_sentinelOnboarding": { + "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", + "type": "Microsoft.SecurityInsights/onboardingStates", + "apiVersion": "2025-09-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "default", + "properties": {}, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { + "copy": { + "name": "logAnalyticsWorkspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "140290971998938797" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14482465616812596213" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedStorageAccounts": { + "copy": { + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" + }, + "storageAccountIds": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14864721709229272590" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": "[parameters('storageAccountIds')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" + }, + "etag": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + }, + "category": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" + }, + "query": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17904092372918022238" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] + }, + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17943947755417749524" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_dataSources": { + "copy": { + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" + }, + "kind": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "15360290236166491819" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "18383178824663161801" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10255889523646649592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" + }, + "primarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The primary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" + }, + "secondarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The secondary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.name.value]" + }, + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." + }, + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + } + }, + "applicationInsights": { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appi-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "retentionInDays": { + "value": 365 + }, + "kind": { + "value": "web" + }, + "disableIpMasking": { + "value": false + }, + "flowType": { + "value": "Bluefield" + }, + "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17358780145253914698" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "flowType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." + } + }, + "requestSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Purge data immediately after 30 days." + } + }, + "ingestionMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ApplicationInsights", + "ApplicationInsightsWithDiagnosticSettings", + "LogAnalytics" + ], + "metadata": { + "description": "Optional. Indicates the flow of the ingestion." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/components@2020-02-02#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]", + "Flow_Type": "[parameters('flowType')]", + "Request_Source": "[parameters('requestSource')]", + "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", + "IngestionMode": "[parameters('ingestionMode')]" + } + }, + "appInsights_roleAssignments": { + "copy": { + "name": "appInsights_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_diagnosticSettings": { + "copy": { + "name": "appInsights_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5059808225314360251" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "appInsights" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights component was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference('appInsights').AppId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "avmManagedIdentity": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('identityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + "avmContainerRegistry": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "acrPullPrincipalIds": { + "value": [ + "[reference('avmContainerRegistryReader').outputs.principalId.value]" + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8138805991948000285" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user for the registry." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." + } + }, + "acrPullPrincipalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Principal IDs to assign AcrPull role." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable private networking." + } + }, + "privateEndpointSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for private endpoint." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Private DNS zone resource IDs for private endpoint." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Azure telemetry collection." + } + } + }, + "variables": { + "copy": [ + { + "name": "roleAssignments", + "count": "[length(parameters('acrPullPrincipalIds'))]", + "input": { + "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", + "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", + "principalType": "ServicePrincipal" + } + }, + { + "name": "dnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" + } + } + ], + "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "acrSku": { + "value": "[parameters('sku')]" + }, + "acrAdminUserEnabled": { + "value": "[parameters('adminUserEnabled')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "exportPolicyStatus": { + "value": "[parameters('exportPolicyStatus')]" + }, + "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[variables('privateEndpointConfig')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1509121545318808417" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR)." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "credentialSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a credential set." + } + }, + "scopeMapsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" + }, + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a scope map." + } + }, + "cacheRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cache rule." + } + }, + "replicationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" + }, + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replication." + } + }, + "taskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties for the task." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The step properties for the task." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The trigger properties for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the task at the time the operation was called." + }, + "nullable": true + }, + "timeout": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The agent configuration for the task." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." + } + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The log template for the task to use when creating logs in Log Analytics." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a task." + } + }, + "tokenType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map which defines the permissions for this token." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" + }, + "description": "Optional. The status of the token at the time the operation was called." + }, + "nullable": true + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." + } + } + } + }, + "webhookType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the webhook at the time the operation was called." + }, + "nullable": true + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + }, + "description": "Optional. Custom headers that will be added to the webhook notifications." + }, + "nullable": true + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a webhook." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "description": "The type for auth credentials.", + "__bicep_imported_from!": { + "sourceTemplate": "credential-set/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "autoGeneratedDomainNameLabelScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse", + "Unsecure" + ], + "metadata": { + "description": "Optional. The domain name label reuse scope." + } + }, + "roleAssignmentMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AbacRepositoryPermissions", + "LegacyRegistryPermissions" + ], + "metadata": { + "description": "Optional. The registry permissions role assignment mode." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "items": { + "$ref": "#/definitions/replicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/webhookType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "items": { + "$ref": "#/definitions/cacheRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialSetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/scopeMapsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Scope maps setting." + } + }, + "tokens": { + "type": "array", + "items": { + "$ref": "#/definitions/tokenType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tokens to create for the container registry." + } + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/definitions/taskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of ACR Tasks to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", + "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", + "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", + "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", + "roleAssignmentMode": "[parameters('roleAssignmentMode')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "registry_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3787322352564227867" + }, + "name": "Container Registries scope maps", + "description": "This module deploys an Azure Container Registry (ACR) scope map." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6219097750044645017" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13412699468141336519" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set." + }, + "definitions": { + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for auth credentials." + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1319901650921923538" + }, + "name": "Container Registry Cache", + "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "cacheRule": { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_tokens": { + "copy": { + "name": "registry_tokens", + "count": "[length(coalesce(parameters('tokens'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "scopeMapResourceId": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5970335582661416899" + }, + "name": "Container Registries Tokens", + "description": "Deploys an Azure Container Registry (ACR) Token." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map to which the token will be associated with." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the token. Default is enabled." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + }, + "description": "Optional. The credentials associated with the token for authentication." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "token": { + "type": "Microsoft.ContainerRegistry/registries/tokens", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "scopeMapId": "[parameters('scopeMapResourceId')]", + "status": "[parameters('status')]", + "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the token." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the token was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the token." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_scopeMaps" + ] + }, + "registry_tasks": { + "copy": { + "name": "registry_tasks", + "count": "[length(coalesce(parameters('tasks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "platform": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" + }, + "step": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" + }, + "trigger": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" + }, + "timeout": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" + }, + "agentConfiguration": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" + }, + "agentPoolName": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" + }, + "isSystemTask": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" + }, + "logTemplate": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2468771835002458415" + }, + "name": "Container Registries Tasks", + "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." + }, + "definitions": { + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties against which the task has to run." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The properties that describe all triggers for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. The current status of task." + } + }, + "timeout": { + "type": "int", + "defaultValue": 3600, + "minValue": 300, + "maxValue": 28800, + "metadata": { + "description": "Optional. Run timeout in seconds." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The machine configuration of the run agent." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The dedicated agent pool for the task." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" + }, + "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + }, + "nullable": true + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The value of this property indicates whether the task resource is system task or not." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The template that describes the repository and tag information for run log artifact." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "task": { + "type": "Microsoft.ContainerRegistry/registries/tasks", + "apiVersion": "2025-03-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "agentConfiguration": "[parameters('agentConfiguration')]", + "agentPoolName": "[parameters('agentPoolName')]", + "credentials": "[parameters('credentials')]", + "isSystemTask": "[parameters('isSystemTask')]", + "logTemplate": "[parameters('logTemplate')]", + "platform": "[parameters('platform')]", + "status": "[parameters('status')]", + "step": "[parameters('step')]", + "timeout": "[parameters('timeout')]", + "trigger": "[parameters('trigger')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the task." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the task was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the task." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('task', '2025-03-01-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3200175097987099858" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "securestring", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_replications" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference('registry').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2025-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Azure container registry." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "avmContainerRegistryReader", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", + "virtualNetwork" + ] + }, + "avmStorageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "minimumTlsVersion": { + "value": "TLS1_2" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", + "ipRules": [] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "supportsHttpsTrafficOnly": { + "value": true + }, + "accessTier": { + "value": "Hot" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1254456195180100771" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoints output." + } + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network configuration." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey1 secret name to create." + } + }, + "connectionString1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString1 secret name to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey2 secret name to create." + } + }, + "connectionString2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString2 secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the exported secrets." + } + }, + "localUserType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a local user." + } + }, + "blobServiceType": { + "type": "object", + "properties": { + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/blobCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "versionDeletePolicyDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a blob service." + } + }, + "fileServiceType": { + "type": "object", + "properties": { + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." + }, + "nullable": true + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "nullable": true + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/fileCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a file service." + } + }, + "queueServiceType": { + "type": "object", + "properties": { + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/queueCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a queue service." + } + }, + "tableServiceType": { + "type": "object", + "properties": { + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/tableCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a table service." + } + }, + "objectReplicationPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." + } + }, + "destinationStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the destination storage account." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. The storage account object replication rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy." + } + }, + "_1.immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/container/main.bicep" + } + } + }, + "_2.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "blobCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/_1.immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type of a storage container.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "fileCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a file share.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "object-replication-policy/policy/main.bicep" + } + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "queueCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a queue.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_2.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "tableCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a table.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "extendedLocationZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS", + "Standard_GRS", + "Standard_GZRS", + "Standard_RAGRS", + "Standard_RAGZRS", + "StandardV2_LRS", + "StandardV2_ZRS", + "StandardV2_GRS", + "StandardV2_GZRS", + "Premium_LRS", + "Premium_ZRS", + "PremiumV2_LRS", + "PremiumV2_ZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "Cold" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" + }, + "description": "Optional. Provides the identity based authentication settings for Azure Files." + }, + "nullable": true + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Optional. The Storage Account ManagementPolicies Rules." + }, + "nullable": true + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "$ref": "#/definitions/blobServiceType", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "$ref": "#/definitions/fileServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "$ref": "#/definitions/queueServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "$ref": "#/definitions/tableServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_2", + "TLS1_3" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/localUserType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "sasExpirationAction": { + "type": "string", + "defaultValue": "Log", + "allowedValues": [ + "Block", + "Log" + ], + "metadata": { + "description": "Optional. The SAS expiration action. Allowed values are Block and Log." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "immutableStorageWithVersioning": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" + }, + "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." + }, + "nullable": true + }, + "objectReplicationPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Object replication policies for the storage account." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2025-05-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[variables('formattedManagementPolicies')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4000605059554016072" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Required. The Storage Account ManagementPolicies Rules." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + }, + "storageAccount_localUsers": { + "copy": { + "name": "storageAccount_localUsers", + "count": "[length(coalesce(parameters('localUsers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1801226901235196767" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "468225492069709453" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a storage container." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "container/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false, + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[parameters('defaultServiceVersion')]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "273904034769611992" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an immutability policy." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "defaultValue": {} + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "container_immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15304742179563677019" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "blobServices" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + }, + "corsRules": { + "value": "[tryGet(parameters('fileServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17583198711200998285" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a file share." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." + }, + "defaultValue": {} + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "defaultValue": { + "enabled": true, + "days": 7 + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "provisionedBandwidthMibps": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + }, + "provisionedIops": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10353179772982843397" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]", + "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", + "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + }, + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9644461291744477521" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a queue." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "12812824360066955039" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair that represents queue metadata." + }, + "defaultValue": {} + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" + }, + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + }, + "corsRules": { + "value": "[tryGet(parameters('tableServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10320403358700650147" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11362260974696477885" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13227497656004178962" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_objectReplicationPolicies": { + "copy": { + "name": "storageAccount_objectReplicationPolicies", + "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "destinationAccountResourceId": { + "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" + }, + "enableMetrics": { + "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" + }, + "rules": { + "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1894366578172550759" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "policy/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the parent Storage Account." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "variables": { + "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", + "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", + "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", + "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "destinationPolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", + "subscriptionId": "[variables('destAccountSubscription')]", + "resourceGroup": "[variables('destAccountResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('name'), 'default')]" + }, + "storageAccountName": { + "value": "[variables('destAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "value": "[parameters('rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } + } + } + } + }, + "sourcePolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[reference('destinationPolicy').outputs.policyId.value]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('rules'))]", + "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } + } + } + }, + "dependsOn": [ + "destinationPolicy" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.policyId.value]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2025-06-01', 'full').location]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." + }, + "value": "[reference('storageAccount').primaryEndpoints]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Storage Account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The primary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + }, + "secondaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The secondary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" + }, + "primaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" + }, + "secondaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", + "virtualNetwork" + ] + }, + "avmAiServices": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "projectName": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "projectDescription": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "existingFoundryProjectResourceId": { + "value": "[variables('existingProjectResourceId')]" + }, + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "sku": { + "value": "S0" + }, + "allowProjectManagement": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "kind": { + "value": "AIServices" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('azureAiServiceLocation')]" + } + }, + "customSubDomainName": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" + } + }, + "disableLocalAuth": { + "value": true + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "deployments": { + "value": [ + { + "name": "[parameters('gptModelName')]", + "model": { + "format": "OpenAI", + "name": "[parameters('gptModelName')]", + "version": "[parameters('gptModelVersion')]" + }, + "sku": { + "name": "[parameters('deploymentType')]", + "capacity": "[parameters('gptDeploymentCapacity')]" + }, + "raiPolicyName": "Microsoft.Default" + } + ] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18336251851332975005" + }, + "name": "Cognitive Services", + "description": "This module deploys a Cognitive Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/project.bicep" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "" + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "allowProjectManagement": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable project management feature for AI Foundry." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", + "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2025-01-31-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "cognitiveServiceNew": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "allowProjectManagement": "[parameters('allowProjectManagement')]", + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "cognitiveServiceExisting": { + "condition": "[variables('useExistingService')]", + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "cognitive_service_dependencies": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + } + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + } + }, + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } + }, + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + } + } + } + }, + "dependsOn": [ + "cognitiveServiceNew" + ] + }, + "existing_cognitive_service_dependencies": { + "condition": "[variables('useExistingService')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + } + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + } + }, + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } + }, + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The service endpoint of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" + }, + "endpoints": { + "$ref": "#/definitions/endpointType", + "metadata": { + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "logAnalyticsWorkspace" + ] + }, + "cognitiveServicePrivateEndpoint": { + "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": { + "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", + "properties": { + "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", + "groupIds": [ + "account" + ] + } + } + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "name": "ai-services-dns-zone-cognitiveservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-openai", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-aiservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-contentunderstanding", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" + } + ] + } + }, + "subnetResourceId": { + "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "avmAiServices", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", + "virtualNetwork" + ] + }, + "avmContainerAppEnv": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('cae-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", + "workloadProfiles": { + "value": [ + { + "name": "Consumption", + "workloadProfileType": "Consumption" + } + ] + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "platformReservedCidr": { + "value": "172.17.17.0/24" + }, + "platformReservedDnsIP": { + "value": "172.17.17.17" + }, + "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", + "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11924518395502120940" + }, + "name": "App ManagedEnvironments", + "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." + }, + "definitions": { + "certificateType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the certificate." + } + }, + "certificateType": { + "type": "string", + "allowedValues": [ + "ImagePullTrustedCA", + "ServerSSLCertificate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location for the resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a certificate." + } + }, + "storageType": { + "type": "object", + "properties": { + "accessMode": { + "type": "string", + "allowedValues": [ + "ReadOnly", + "ReadWrite" + ], + "metadata": { + "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. File share name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the storage." + } + }, + "appLogsConfigurationType": { + "type": "object", + "discriminator": { + "propertyName": "destination", + "mapping": { + "azure-monitor": { + "$ref": "#/definitions/appLogsConfigurationMonitorType" + }, + "log-analytics": { + "$ref": "#/definitions/appLogsConfigurationLawType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the App Logs Configuration." + } + }, + "appLogsConfigurationMonitorType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "azure-monitor" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using azure-monitor." + } + }, + "appLogsConfigurationLawType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "log-analytics" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Existing Log Analytics Workspace resource ID." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using log-analytics." + } + }, + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } + }, + "metadata": { + "description": "The type for the certificate's key vault properties.", + "__bicep_imported_from!": { + "sourceTemplate": "certificate/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string." + } + }, + "daprConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" + }, + "description": "Optional. The configuration of Dapr component." + }, + "nullable": true + }, + "ingressConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" + }, + "description": "Optional. Ingress configuration for the Managed Environment." + }, + "nullable": true + }, + "kedaConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" + }, + "description": "Optional. The configuration of Keda component." + }, + "nullable": true + }, + "peerAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" + }, + "description": "Optional. Peer authentication settings for the Managed Environment." + }, + "nullable": true + }, + "daprAIConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." + } + }, + "daprAIInstrumentationKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." + } + }, + "dockerBridgeCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "infrastructureSubnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "internal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedDnsIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "peerTrafficEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not to encrypt peer traffic." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether to allow or block all public traffic." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not this Managed Environment is zone-redundant." + } + }, + "certificatePassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Password of the certificate used by the custom domain." + } + }, + "certificateValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Certificate to use for the custom domain. PFX or PEM." + } + }, + "dnsSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. DNS suffix for the environment domain." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "openTelemetryConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" + }, + "description": "Optional. Open Telemetry configuration." + }, + "nullable": true + }, + "workloadProfiles": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" + }, + "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." + }, + "nullable": true + }, + "infrastructureResourceGroupName": { + "type": "string", + "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", + "metadata": { + "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "storages": { + "type": "array", + "items": { + "$ref": "#/definitions/storageType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of storages to mount on the environment." + } + }, + "certificate": { + "$ref": "#/definitions/certificateType", + "nullable": true, + "metadata": { + "description": "Optional. A Managed Environment Certificate." + } + }, + "appLogsConfiguration": { + "$ref": "#/definitions/appLogsConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The AppLogsConfiguration for the Managed Environment." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-11-01", + "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-02-01", + "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" + }, + "managedEnvironment": { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "appInsightsConfiguration": { + "connectionString": "[parameters('appInsightsConnectionString')]" + }, + "daprConfiguration": "[parameters('daprConfiguration')]", + "ingressConfiguration": "[parameters('ingressConfiguration')]", + "kedaConfiguration": "[parameters('kedaConfiguration')]", + "peerAuthentication": "[parameters('peerAuthentication')]", + "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", + "daprAIConnectionString": "[parameters('daprAIConnectionString')]", + "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", + "customDomainConfiguration": { + "certificatePassword": "[parameters('certificatePassword')]", + "certificateValue": "[parameters('certificateValue')]", + "dnsSuffix": "[parameters('dnsSuffix')]", + "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" + }, + "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", + "peerTrafficConfiguration": { + "encryption": { + "enabled": "[parameters('peerTrafficEncryption')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "vnetConfiguration": { + "internal": "[parameters('internal')]", + "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", + "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", + "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", + "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" + }, + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]", + "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "managedEnvironment_roleAssignments": { + "copy": { + "name": "managedEnvironment_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_storage": { + "copy": { + "name": "managedEnvironment_storage", + "count": "[length(coalesce(parameters('storages'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" + }, + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "kind": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + }, + "accessMode": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + }, + "storageAccountName": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "945327737463253676" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "managedEnvironmentName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "accessMode": { + "type": "string", + "metadata": { + "description": "Required. The access mode for the storage." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "storage": { + "type": "Microsoft.App/managedEnvironments/storages", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "properties": { + "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", + "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the file share." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the file share was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_certificate": { + "condition": "[not(empty(parameters('certificate')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" + }, + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "certificateKeyVaultProperties": { + "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" + }, + "certificateType": { + "value": "[tryGet(parameters('certificate'), 'certificateType')]" + }, + "certificateValue": { + "value": "[tryGet(parameters('certificate'), 'certificateValue')]" + }, + "certificatePassword": { + "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" + }, + "location": { + "value": "[tryGet(parameters('certificate'), 'location')]" + }, + "tags": { + "value": "[tryGet(parameters('certificate'), 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "574133184207535827" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "definitions": { + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the certificate's key vault properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment Certificate." + } + }, + "managedEnvironmentName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference to the certificate to use for the custom domain." + } + }, + "certificateType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ServerSSLCertificate", + "ImagePullTrustedCA" + ], + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "managedEnvironmentCertificate": { + "type": "Microsoft.App/managedEnvironments/certificates", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", + "certificateType": "[parameters('certificateType')]", + "password": "[parameters('certificatePassword')]", + "value": "[parameters('certificateValue')]" + }, + "tags": "[parameters('tags')]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the certificate was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedEnvironment" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Managed Environment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Managed Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Managed Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('managedEnvironment').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The IP address of the Managed Environment." + }, + "value": "[reference('managedEnvironment').staticIp]" + }, + "domainVerificationId": { + "type": "string", + "metadata": { + "description": "The domain verification id for custom domains." + }, + "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "virtualNetwork" + ] + }, + "avmContainerRegistryReader": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } + } + } + } + }, + "avmContainerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_API": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_Web": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 3000 + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_API_BASE_URL", + "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" + }, + { + "name": "APP_WEB_CLIENT_ID", + "value": "" + }, + { + "name": "APP_WEB_AUTHORITY", + "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" + }, + { + "name": "APP_WEB_SCOPE", + "value": "" + }, + { + "name": "APP_API_SCOPE", + "value": "" + }, + { + "name": "APP_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_POST_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_CONSOLE_LOG_ENABLED", + "value": "false" + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp_API", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_Workflow": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmCosmosDB": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "mongodbDatabases": { + "value": [ + { + "name": "default", + "tag": "default database" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "databaseAccountOfferType": { + "value": "Standard" + }, + "enableAutomaticFailover": { + "value": false + }, + "serverVersion": { + "value": "7.0" + }, + "capabilitiesToAdd": { + "value": [ + "EnableMongo" + ] + }, + "defaultConsistencyLevel": { + "value": "Session" + }, + "maxIntervalInSeconds": { + "value": 5 + }, + "maxStalenessPrefix": { + "value": 100 + }, + "zoneRedundant": { + "value": false + }, + "networkRestrictions": { + "value": { + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", + "ipRules": [], + "virtualNetworkRules": [] + } + }, + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1772014800591596213" + }, + "name": "Azure Cosmos DB account", + "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group ID for the private endpoint group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses for the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "failoverLocationType": { + "type": "object", + "properties": { + "failoverPriority": { + "type": "int", + "metadata": { + "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." + } + }, + "isZoneRedundant": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." + } + }, + "locationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the region." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the failover location." + } + }, + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." + } + }, + "sqlRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/nestedSqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." + } + }, + "networkRestrictionType": { + "type": "object", + "properties": { + "ipRules": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." + } + }, + "networkAclBypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." + } + }, + "publicNetworkAccess": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." + } + }, + "virtualNetworkRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of a subnet." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." + } + }, + "networkAclBypassResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network restriction." + } + }, + "gremlinDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a gremlin databae." + } + }, + "mongoDbType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a mongo databae." + } + }, + "sqlDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a sql database." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "cassandraStandaloneRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." + } + }, + "cassandraRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "cassandraKeyspaceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraTableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraViewType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB Cassandra keyspace." + } + }, + "defaultIdentityType": { + "type": "object", + "discriminator": { + "propertyName": "name", + "mapping": { + "FirstPartyIdentity": { + "$ref": "#/definitions/defaultIdentityFirstPartyType" + }, + "SystemAssignedIdentity": { + "$ref": "#/definitions/defaultIdentitySystemAssignedType" + }, + "UserAssignedIdentity": { + "$ref": "#/definitions/defaultIdentityUserAssignedType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the default identity." + } + }, + "defaultIdentityFirstPartyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "FirstPartyIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentitySystemAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "SystemAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentityUserAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "UserAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the user assigned identity to use as the default identity." + } + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-role-definition/main.bicep" + } + } + }, + "cassandraTableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "description": "The type of a Cassandra table.", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "tableType" + } + } + }, + "cassandraViewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "description": "The type of a Cassandra view (materialized view).", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "viewType" + } + } + }, + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "description": "The type of a collection.", + "__bicep_imported_from!": { + "sourceTemplate": "mongodb-database/main.bicep" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "description": "The type of a container.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-database/main.bicep" + } + } + }, + "customerManagedKeyAndVaultOnlyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "description": "The type of a graph.", + "__bicep_imported_from!": { + "sourceTemplate": "gremlin-database/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "nestedSqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "description": "The type for the SQL Role Assignments.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-role-definition/main.bicep", + "originalIdentifier": "sqlRoleAssignmentType" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the account." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Defaults to the current resource group scope location. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "databaseAccountOfferType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], + "metadata": { + "description": "Optional. The offer type for the account. Defaults to \"Standard\"." + } + }, + "failoverLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/failoverLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." + } + }, + "defaultConsistencyLevel": { + "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], + "metadata": { + "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." + } + }, + "disableLocalAuthentication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." + } + }, + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." + } + }, + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions. Defaults to true." + } + }, + "enableFreeTier": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." + } + }, + "enableMultipleWriteLocations": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." + } + }, + "disableKeyBasedMetadataWriteAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." + } + }, + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." + } + }, + "serverVersion": { + "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2", + "5.0", + "6.0", + "7.0" + ], + "metadata": { + "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." + } + }, + "sqlDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." + } + }, + "mongodbDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/mongoDbType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." + } + }, + "gremlinDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/gremlinDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." + } + }, + "cassandraKeyspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraKeyspaceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "totalThroughputLimit": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of control plane Azure role-based access control assignments." + } + }, + "sqlRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." + } + }, + "cassandraRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings for the service." + } + }, + "capabilitiesToAdd": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless", + "EnableNoSQLVectorSearch", + "EnableNoSQLFullTextSearch", + "EnableMaterializedViews", + "DeleteAllItemsByPartitionKey" + ], + "metadata": { + "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." + } + }, + "backupPolicyType": { + "type": "string", + "defaultValue": "Continuous", + "allowedValues": [ + "Periodic", + "Continuous" + ], + "metadata": { + "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." + } + }, + "backupPolicyContinuousTier": { + "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], + "metadata": { + "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." + } + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." + } + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, + "metadata": { + "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." + } + }, + "backupStorageRedundancy": { + "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], + "metadata": { + "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." + } + }, + "networkRestrictions": { + "$ref": "#/definitions/networkRestrictionType", + "defaultValue": { + "ipRules": [], + "virtualNetworkRules": [], + "publicNetworkAccess": "Disabled" + }, + "metadata": { + "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "Tls12", + "allowedValues": [ + "Tls12" + ], + "metadata": { + "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." + } + }, + "enableBurstCapacity": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." + } + }, + "enableCassandraConnector": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." + } + }, + "enablePartitionMerge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." + } + }, + "enablePerRegionPerPartitionAutoscale": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." + } + }, + "analyticalStorageConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" + }, + "description": "Optional. Analytical storage specific properties." + }, + "nullable": true + }, + "cors": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" + }, + "description": "Optional. The CORS policy for the Cosmos DB database account." + }, + "nullable": true + }, + "defaultIdentity": { + "$ref": "#/definitions/defaultIdentityType", + "defaultValue": { + "name": "FirstPartyIdentity" + }, + "metadata": { + "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInControlPlaneRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" + }, + "databaseAccount": { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", + "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", + "dependsOn": [ + "cMKKeyVault::cMKKey" + ] + }, + "databaseAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_diagnosticSettings": { + "copy": { + "name": "databaseAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_roleAssignments": { + "copy": { + "name": "databaseAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlDatabases": { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "3972888645334640168" + }, + "name": "DocumentDB Database Account SQL Databases", + "description": "This module deploys a SQL Database in a CosmosDB Account." + }, + "definitions": { + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a container." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "container": { + "copy": { + "name": "container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "conflictResolutionPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + }, + "defaultTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "kind": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + }, + "paths": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + }, + "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", + "uniqueKeyPolicyKeys": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "4781880351108045502" + }, + "name": "DocumentDB Database Account SQL Database Containers", + "description": "This module deploys a SQL Database Container in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "variables": { + "copy": [ + { + "name": "partitionKeyPaths", + "count": "[length(parameters('paths'))]", + "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + } + ] + }, + "resources": { + "databaseAccount::sqlDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "container": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlRoleDefinitions": { + "copy": { + "name": "databaseAccount_sqlRoleDefinitions", + "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "dataActions": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" + }, + "roleName": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "sqlRoleAssignments": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "8514367433037227852" + }, + "name": "DocumentDB Database Account SQL Role Definitions.", + "description": "This module deploys a SQL Role Definision in a CosmosDB Account." + }, + "definitions": { + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SQL Role Assignments." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionIdOrName": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The role name of the SQL Role Definition." + }, + "value": "[reference('sqlRoleDefinition').roleName]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionIdOrName": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_sqlDatabases", + "databaseAccount_sqlRoleDefinitions" + ] + }, + "databaseAccount_cassandraRoleDefinitions": { + "copy": { + "name": "databaseAccount_cassandraRoleDefinitions", + "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "roleName": { + "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "dataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" + }, + "notDataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "cassandraRoleAssignments": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10787709019875067397" + }, + "name": "DocumentDB Database Account Cassandra Role Definitions.", + "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." + }, + "definitions": { + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]", + "notDataActions": "[parameters('notDataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cassandra role definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cassandra role definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the cassandra role definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_cassandraKeyspaces", + "databaseAccount_cassandraRoleDefinitions" + ] + }, + "databaseAccount_mongodbDatabases": { + "copy": { + "name": "databaseAccount_mongodbDatabases", + "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "collections": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "autoscaleSettings": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "13897098552792121791" + }, + "name": "DocumentDB Database Account MongoDB Databases", + "description": "This module deploys a MongoDB Database within a CosmosDB Account." + }, + "definitions": { + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a collection." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "mongodbDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "mongodbDatabase_collections": { + "copy": { + "name": "mongodbDatabase_collections", + "count": "[length(coalesce(parameters('collections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "mongodbDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + }, + "indexes": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + }, + "shardKey": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "16151461445994734468" + }, + "name": "DocumentDB Database Account MongoDB Database Collections", + "description": "This module deploys a MongoDB Database Collection." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "mongodbDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]", + "indexes": "[parameters('indexes')]", + "shardKey": "[parameters('shardKey')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database collection." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database collection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "mongodbDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_gremlinDatabases": { + "copy": { + "name": "databaseAccount_gremlinDatabases", + "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "graphs": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11959636451300474346" + }, + "name": "DocumentDB Database Account Gremlin Databases", + "description": "This module deploys a Gremlin Database within a CosmosDB Account." + }, + "definitions": { + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a graph." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + } + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "gremlinDatabase_gremlinGraphs": { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(coalesce(parameters('graphs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "partitionKeyPaths": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10487122333182352122" + }, + "name": "DocumentDB Database Accounts Gremlin Databases Graphs", + "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount::gremlinDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinGraph": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": "[parameters('indexingPolicy')]", + "partitionKey": { + "paths": "[parameters('partitionKeyPaths')]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "gremlinDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_tables": { + "copy": { + "name": "databaseAccount_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1787500858429182824" + }, + "name": "Azure Cosmos DB account tables", + "description": "This module deploys a table within an Azure Cosmos DB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "table": { + "type": "Microsoft.DocumentDB/databaseAccounts/tables", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraKeyspaces": { + "copy": { + "name": "databaseAccount_cassandraKeyspaces", + "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" + }, + "views": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15257396763463366586" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces", + "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." + }, + "definitions": { + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra table." + } + }, + "viewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra view (materialized view)." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/viewType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraKeyspace": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "cassandraKeyspace_tables": { + "copy": { + "name": "cassandraKeyspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "schema": { + "value": "[parameters('tables')[copyIndex()].schema]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + }, + "throughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "defaultTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15998065591386988132" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Tables", + "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra table resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the Cassandra table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "defaultTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraTable": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "schema": "[parameters('schema')]", + "defaultTtl": "[parameters('defaultTtl')]", + "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + }, + "cassandraKeyspace_views": { + "copy": { + "name": "cassandraKeyspace_views", + "count": "[length(parameters('views'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('views')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "viewDefinition": { + "value": "[parameters('views')[copyIndex()].viewDefinition]" + }, + "throughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6617803098467821091" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Views", + "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra view." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags of the Cassandra view resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraView": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "viewDefinition": "[parameters('viewDefinition')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra view." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra view." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra view was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra keyspace." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra keyspace." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra keyspace was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_privateEndpoints": { + "copy": { + "name": "databaseAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the database account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the database account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the database account was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the database account." + }, + "value": "[reference('databaseAccount').documentEndpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "primaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" + }, + "primaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" + }, + "primaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" + }, + "primaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" + }, + "secondaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" + }, + "secondaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" + }, + "secondaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" + }, + "secondaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" + } + } + } + }, + "dependsOn": [ + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", + "virtualNetwork" + ] + }, + "avmAiSearch": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('srch-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "basic" + }, + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8530209533589901450" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Diagnostic settings for monitoring." + } + }, + "privateEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Private endpoint configurations." + } + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of role assignments to create on the AI Search service." + } + } + }, + "resources": { + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" + } + }, + "searchServiceUpdate": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.search.update.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "sku": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": "[equals(parameters('managedIdentityType'), 'SystemAssigned')]" + } + }, + "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "6207719545398489494" + }, + "name": "Search Services", + "description": "This module deploys a Search Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the API Admin keys generated by the modules." + } + }, + "primaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAdminKey secret name to create." + } + }, + "secondaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAdminKey secret name to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." + } + }, + "authOptions": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/authOptions" + }, + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + }, + "nullable": true + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "computeType": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Confidential", + "Default" + ], + "metadata": { + "description": "Optional. The compute type of the search service." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "dataExfiltrationProtections": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Optional. A list of data exfiltration scenarios that are explicitly disallowed for the search service. Currently, the only supported value is 'All' to disable all possible data export scenarios with more fine grained controls planned for the future." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings for all Resources in the solution." + } + }, + "networkRuleSet": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/networkRuleSet" + }, + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + }, + "nullable": true + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to help categorize the resource in the Azure portal." + }, + "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', '')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "authOptions": "[parameters('authOptions')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]", + "computeType": "[parameters('computeType')]", + "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" + } + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "2115224445601868607" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource." + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "696453183181258843" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2025-05-01', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[reference('searchService').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryKey": { + "type": "securestring", + "metadata": { + "description": "The primary admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" + }, + "secondaryKey": { + "type": "securestring", + "metadata": { + "description": "The secondaryKey admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." + }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" + } + } + } + } + }, + "avmAppConfig": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('location')]" + } + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "sku": { + "value": "Standard" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "disableLocalAuth": { + "value": false + }, + "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + } + ] + }, + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_PROCESS", + "value": "Processes" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMA", + "value": "Schemas" + }, + { + "name": "APP_COSMOS_DATABASE", + "value": "ContentProcess" + }, + { + "name": "APP_CPS_CONFIGURATION", + "value": "cps-configuration" + }, + { + "name": "APP_CPS_MAX_FILESIZE_MB", + "value": "20" + }, + { + "name": "APP_CPS_PROCESSES", + "value": "cps-processes" + }, + { + "name": "APP_MESSAGE_QUEUE_EXTRACT", + "value": "content-pipeline-extract-queue" + }, + { + "name": "APP_MESSAGE_QUEUE_INTERVAL", + "value": "5" + }, + { + "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", + "value": "180" + }, + { + "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", + "value": "10" + }, + { + "name": "APP_PROCESS_STEPS", + "value": "extract,map,evaluate,save" + }, + { + "name": "APP_STORAGE_BLOB_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" + }, + { + "name": "APP_STORAGE_QUEUE_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" + }, + { + "name": "APP_COSMOS_CONNSTR", + "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", + "value": "claimprocesses" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCHES", + "value": "batches" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMASET", + "value": "Schemasets" + }, + { + "name": "APP_CPS_PROCESS_BATCH", + "value": "process-batch" + }, + { + "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", + "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" + }, + { + "name": "APP_CPS_POLL_INTERVAL_SECONDS", + "value": "3" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference('avmStorageAccount').outputs.name.value]" + }, + { + "name": "CLAIM_PROCESS_QUEUE_NAME", + "value": "claim-process-queue" + }, + { + "name": "DEAD_LETTER_QUEUE_NAME", + "value": "claim-process-dead-letter-queue" + }, + { + "name": "AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", + "value": "[parameters('gptModelName')]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_OPENAI_ENDPOINT_BASE", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", + "value": "" + }, + { + "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", + "value": "" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + }, + { + "name": "GLOBAL_LLM_SERVICE", + "value": "AzureOpenAI" + }, + { + "name": "GPT5_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "GPT5_CHAT_DEPLOYMENT_NAME", + "value": "gpt-5" + }, + { + "name": "GPT5_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "PHI4_API_VERSION", + "value": "2024-05-01-preview" + }, + { + "name": "PHI4_CHAT_DEPLOYMENT_NAME", + "value": "phi-4" + }, + { + "name": "PHI4_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + } + ] + }, + "publicNetworkAccess": { + "value": "Enabled" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the app configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the app configuration." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration store was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the app configuration." + }, + "value": "[reference('configurationStore').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the app configuration." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } + } + } + }, + "dependsOn": [ + "avmAiServices", + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Web", + "avmContainerApp_Workflow", + "avmCosmosDB", + "avmStorageAccount", + "logAnalyticsWorkspace" + ] + }, + "avmAppConfig_update": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "privateEndpoints": { + "value": [ + { + "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", + "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "name": "appconfig-dns-zone-group", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" + } + ] + }, + "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the app configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the app configuration." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration store was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the app configuration." + }, + "value": "[reference('configurationStore').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the app configuration." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } + } + } + }, + "dependsOn": [ + "avmAppConfig", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", + "virtualNetwork" + ] + }, + "avmContainerApp_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" + ] + }, + "avmContainerApp_API_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" + ] + }, + "avmContainerApp_Workflow_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + } + }, + "outputs": { + "CONTAINER_WEB_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for Web App." + }, + "value": "[reference('avmContainerApp_Web').outputs.name.value]" + }, + "CONTAINER_API_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for API." + }, + "value": "[reference('avmContainerApp_API').outputs.name.value]" + }, + "CONTAINER_WEB_APP_FQDN": { + "type": "string", + "metadata": { + "description": "The FQDN of the Container App." + }, + "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" + }, + "CONTAINER_API_APP_FQDN": { + "type": "string", + "metadata": { + "description": "The FQDN of the Container App API." + }, + "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" + }, + "CONTAINER_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for APP." + }, + "value": "[reference('avmContainerApp').outputs.name.value]" + }, + "CONTAINER_WORKFLOW_APP_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Container App used for Workflow." + }, + "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" + }, + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "metadata": { + "description": "The user identity resource ID used fot the Container APP." + }, + "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", + "metadata": { + "description": "The user identity Principal ID used fot the Container APP." + }, + "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "metadata": { + "description": "The login server of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "metadata": { + "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." + }, + "value": "[reference('avmAiServices').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "metadata": { + "description": "The resource group the resources were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "SOLUTION_NAME": { + "type": "string", + "metadata": { + "description": "The solution name." + }, + "value": "[parameters('solutionName')]" + } + } +} \ No newline at end of file diff --git a/infra/bicep/main.bicep b/infra/bicep/main.bicep new file mode 100644 index 00000000..3a3b9f19 --- /dev/null +++ b/infra/bicep/main.bicep @@ -0,0 +1,794 @@ +targetScope = 'resourceGroup' + +metadata name = 'Content Processing Solution Accelerator - Bicep' +metadata description = 'Deploys Content Processing resources using the restored private-repo module interfaces.' + +@minLength(3) +@maxLength(20) +param solutionName string = 'cps' + +@metadata({ azd: { type: 'location' } }) +param location string + +@metadata({ azd: { type: 'location' } }) +param azureAiServiceLocation string + +param gptModelName string = 'gpt-5.1' +param containerRegistryEndpoint string = '' +param imageTag string = 'latest_v2' +param enablePrivateNetworking bool = false +param enableMonitoring bool = false +param enableRedundancy bool = false +param enableScalability bool = false +param enableTelemetry bool = true +param enablePurgeProtection bool = false +param tags object = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location +} + +var uniqueToken = substring(uniqueString(subscription().subscriptionId, resourceGroup().id, solutionName), 0, 5) +var solutionSuffix = toLower(replace(replace(replace('${solutionName}${uniqueToken}', '-', ''), '_', ''), '.', '')) + +var managedIdentityName = 'id-${solutionSuffix}' +var containerRegistryName = replace('cr${solutionSuffix}', '-', '') +var storageAccountName = take(replace('st${solutionSuffix}', '-', ''), 24) +var cosmosDbName = 'cosmos-${solutionSuffix}' +var cosmosDatabaseName = 'contentprocessing' +var cosmosContainerName = 'documents' +var aiServicesName = 'aif-${solutionSuffix}' +var aiProjectName = 'proj-${solutionSuffix}' +var aiSearchName = 'srch-${solutionSuffix}' +var appConfigurationName = 'appcs-${solutionSuffix}' +var containerAppEnvironmentName = 'cae-${solutionSuffix}' +var contentProcessorAppName = 'ca-${solutionSuffix}-app' +var contentProcessorApiName = 'ca-${solutionSuffix}-api' +var contentProcessorWebName = 'ca-${solutionSuffix}-web' +var contentProcessorWorkflowName = 'ca-${solutionSuffix}-wkfl' +var modelDeploymentName = 'gpt-${solutionSuffix}' +var storageContainerName = 'content' +var storageQueueName = 'content' + +var acrPullRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') +var storageBlobDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') +var storageQueueDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88') +var appConfigurationDataReaderRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071') +var cognitiveServicesOpenAiUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd') +var cognitiveServicesUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908') +var azureAiDeveloperRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee') + +module logAnalytics './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { + name: take('module.log-analytics.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + location: location + tags: tags + } +} + +module appInsights './modules/monitoring/app-insights.bicep' = if (enableMonitoring) { + name: take('module.app-insights.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + location: location + workspaceResourceId: logAnalytics!.outputs.resourceId + tags: tags + } +} + +module managedIdentity './modules/identity/managed-identity.bicep' = { + name: take('module.managed-identity.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + identityName: managedIdentityName + location: location + tags: tags + } +} + +module containerRegistry './modules/compute/container-registry.bicep' = { + name: take('module.container-registry.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: containerRegistryName + location: location + sku: enableRedundancy ? 'Premium' : 'Standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + tags: tags + } +} + +module storageAccount './modules/data/storage-account.bicep' = { + name: take('module.storage-account.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: storageAccountName + location: location + skuName: enableRedundancy ? 'Standard_ZRS' : 'Standard_LRS' + containers: [ + { + name: storageContainerName + publicAccess: 'None' + } + ] + tags: tags + } +} + +resource storageAccountResource 'Microsoft.Storage/storageAccounts@2025-08-01' existing = { + name: storageAccountName +} + +resource queueService 'Microsoft.Storage/storageAccounts/queueServices@2025-08-01' = { + parent: storageAccountResource + name: 'default' +} + +resource storageQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@2025-08-01' = { + parent: queueService + name: storageQueueName +} + +resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { + name: cosmosDbName + location: location + kind: 'MongoDB' + tags: tags + properties: { + databaseAccountOfferType: 'Standard' + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: enableRedundancy + } + ] + capabilities: [ + { + name: 'EnableMongo' + } + ] + apiProperties: { + serverVersion: '7.0' + } + disableLocalAuth: false + enableAutomaticFailover: false + enableMultipleWriteLocations: false + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + } +} + +resource cosmosMongoDatabase 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2023-04-15' = { + parent: cosmosDb + name: cosmosDatabaseName + properties: { + resource: { + id: cosmosDatabaseName + } + options: {} + } +} + +resource cosmosMongoCollection 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2023-04-15' = { + parent: cosmosMongoDatabase + name: cosmosContainerName + properties: { + resource: { + id: cosmosContainerName + shardKey: { + id: 'Hash' + } + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + ] + } + options: {} + } +} + +module aiFoundry './modules/ai/ai-foundry.bicep' = { + name: take('module.ai-foundry.${solutionSuffix}', 64) + params: { + name: aiServicesName + location: azureAiServiceLocation + principalIds: [] + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + tags: union(tags, { + location: azureAiServiceLocation + }) + } +} + +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesName +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { + parent: aiServicesAccount + name: aiProjectName + location: azureAiServiceLocation + kind: 'AIServices' + identity: { + type: 'SystemAssigned' + } + tags: union(tags, { + location: azureAiServiceLocation + }) + properties: {} +} + +module modelDeployment './modules/ai/ai-foundry-model-deployment.bicep' = { + name: take('module.ai-model.${solutionSuffix}', 64) + params: { + aiServicesAccountName: aiFoundry.outputs.name + deploymentName: modelDeploymentName + modelName: gptModelName + skuName: 'GlobalStandard' + skuCapacity: 10 + } +} + +module aiSearch './modules/ai/ai-search.bicep' = { + name: take('module.ai-search.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: aiSearchName + location: location + replicaCount: enableRedundancy ? 2 : 1 + partitionCount: enableScalability ? 2 : 1 + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + tags: tags + } +} + +module containerAppEnvironment './modules/compute/container-app-environment.bicep' = { + name: take('module.container-app-environment.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: containerAppEnvironmentName + location: location + logAnalyticsWorkspaceResourceId: enableMonitoring ? logAnalytics!.outputs.resourceId : '' + zoneRedundant: enableRedundancy + tags: tags + } +} + +var effectiveContainerRegistryEndpoint = empty(containerRegistryEndpoint) ? containerRegistry.outputs.loginServer : containerRegistryEndpoint +var apiAppFqdn = '${contentProcessorApiName}.${containerAppEnvironment.outputs.defaultDomain}' +var webAppFqdn = '${contentProcessorWebName}.${containerAppEnvironment.outputs.defaultDomain}' +var workflowAppFqdn = '${contentProcessorWorkflowName}.${containerAppEnvironment.outputs.defaultDomain}' +var cosmosDbEndpoint = 'https://${cosmosDb.name}.mongo.cosmos.azure.com:443/' + +var sharedEnv = [ + { + name: 'APP_CONFIG_ENDPOINT' + value: appConfiguration.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? appInsights!.outputs.connectionString : '' + } +] + +var apiProbes = [ + { + type: 'Liveness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 + periodSeconds: 5 + failureThreshold: 10 + } +] + +var appConfigurationValues = [ + { + name: 'APP_AZURE_OPENAI_ENDPOINT' + value: aiFoundry.outputs.endpoint + } + { + name: 'APP_AZURE_OPENAI_MODEL' + value: gptModelName + } + { + name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' + value: aiFoundry.outputs.endpoint + } + { + name: 'APP_AI_PROJECT_ENDPOINT' + value: aiProject.properties.endpoints['AI Foundry API'] + } + { + name: 'APP_COSMOS_DB_ENDPOINT' + value: cosmosDbEndpoint + } + { + name: 'APP_COSMOS_DB_NAME' + value: cosmosDatabaseName + } + { + name: 'APP_COSMOS_DB_CONTAINER' + value: cosmosContainerName + } + { + name: 'APP_STORAGE_ACCOUNT_NAME' + value: storageAccount.outputs.name + } + { + name: 'APP_STORAGE_BLOB_ENDPOINT' + value: storageAccount.outputs.blobEndpoint + } + { + name: 'APP_STORAGE_QUEUE_ENDPOINT' + value: storageAccount.outputs.serviceEndpoints.queue + } + { + name: 'APP_STORAGE_CONTAINER_NAME' + value: storageContainerName + } + { + name: 'APP_AI_SEARCH_ENDPOINT' + value: aiSearch.outputs.endpoint + } + { + name: 'APP_AI_SEARCH_INDEX' + value: 'content-index' + } + { + name: 'APP_WORKFLOW_APP_ENDPOINT' + value: 'https://${workflowAppFqdn}' + } + { + name: 'APP_API_ENDPOINT' + value: 'https://${apiAppFqdn}' + } + { + name: 'AZURE_OPENAI_API_VERSION' + value: '2025-03-01-preview' + } + { + name: 'AZURE_TRACING_ENABLED' + value: 'True' + } +] + +module appConfiguration './modules/data/app-configuration.bicep' = { + name: take('module.app-config.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: appConfigurationName + location: location + keyValues: appConfigurationValues + tags: tags + } +} + +module contentProcessorApp './modules/compute/container-app.bicep' = { + name: take('module.content-app.${solutionSuffix}', 64) + params: { + name: contentProcessorAppName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + disableIngress: true + containers: [ + { + name: contentProcessorAppName + image: '${effectiveContainerRegistryEndpoint}/contentprocessor:${imageTag}' + resources: { + cpu: 4 + memory: '8Gi' + } + env: concat(sharedEnv, [ + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' + } + ]) + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + scaleSettings: { + minReplicas: enableScalability ? 2 : 1 + maxReplicas: enableScalability ? 3 : 2 + } + tags: tags + } +} + +module contentProcessorApi './modules/compute/container-app.bicep' = { + name: take('module.content-api.${solutionSuffix}', 64) + params: { + name: contentProcessorApiName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + ingressExternal: true + ingressTargetPort: 80 + containers: [ + { + name: contentProcessorApiName + image: '${effectiveContainerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 2 + memory: '4Gi' + } + env: concat(sharedEnv, [ + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ]) + probes: apiProbes + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + scaleSettings: { + minReplicas: 0 + maxReplicas: 10 + } + tags: tags + } +} + +module contentProcessorWeb './modules/compute/container-app.bicep' = { + name: take('module.content-web.${solutionSuffix}', 64) + params: { + name: contentProcessorWebName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + ingressExternal: true + ingressTargetPort: 80 + containers: [ + { + name: contentProcessorWebName + image: '${effectiveContainerRegistryEndpoint}/contentprocessorweb:${imageTag}' + resources: { + cpu: 2 + memory: '4Gi' + } + env: concat(sharedEnv, [ + { + name: 'APP_API_BASE_URL' + value: 'https://${apiAppFqdn}' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWeb' + } + ]) + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + corsPolicy: { + allowedOrigins: [ + 'https://${apiAppFqdn}' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + '*' + ] + } + scaleSettings: { + minReplicas: 0 + maxReplicas: 10 + } + tags: tags + } +} + +module contentProcessorWorkflow './modules/compute/container-app.bicep' = { + name: take('module.content-workflow.${solutionSuffix}', 64) + params: { + name: contentProcessorWorkflowName + location: location + environmentResourceId: containerAppEnvironment.outputs.resourceId + ingressExternal: true + ingressTargetPort: 80 + containers: [ + { + name: contentProcessorWorkflowName + image: '${effectiveContainerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 2 + memory: '4Gi' + } + env: concat(sharedEnv, [ + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ]) + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + managedIdentity.outputs.resourceId + ] + } + registries: [ + { + server: effectiveContainerRegistryEndpoint + identity: managedIdentity.outputs.resourceId + } + ] + scaleSettings: { + minReplicas: 0 + maxReplicas: 10 + } + tags: tags + } +} + +resource containerRegistryResource 'Microsoft.ContainerRegistry/registries@2025-04-01' existing = { + name: containerRegistryName +} + +resource appConfigurationResource 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = { + name: appConfigurationName +} + +resource acrPullAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerRegistryName, managedIdentityName, 'acr-pull') + scope: containerRegistryResource + properties: { + principalId: managedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: acrPullRoleId + } +} + +resource contentProcessorBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorAppName, 'blob') + scope: storageAccountResource + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageBlobDataContributorRoleId + } +} + +resource contentProcessorApiBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorApiName, 'blob') + scope: storageAccountResource + properties: { + principalId: contentProcessorApi.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageBlobDataContributorRoleId + } +} + +resource contentProcessorWorkflowBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorWorkflowName, 'blob') + scope: storageAccountResource + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageBlobDataContributorRoleId + } +} + +resource contentProcessorQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorAppName, 'queue') + scope: storageAccountResource + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageQueueDataContributorRoleId + } +} + +resource contentProcessorApiQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorApiName, 'queue') + scope: storageAccountResource + properties: { + principalId: contentProcessorApi.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageQueueDataContributorRoleId + } +} + +resource contentProcessorWorkflowQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, contentProcessorWorkflowName, 'queue') + scope: storageAccountResource + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: storageQueueDataContributorRoleId + } +} + +resource contentProcessorAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorAppName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorApiAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorApiName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorApi.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorWebAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorWebName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorWeb.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorWorkflowAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, contentProcessorWorkflowName, 'appconfig') + scope: appConfigurationResource + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: appConfigurationDataReaderRoleId + } +} + +resource contentProcessorOpenAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorAppName, 'openai-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesOpenAiUserRoleId + } +} + +resource contentProcessorWorkflowOpenAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorWorkflowName, 'openai-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesOpenAiUserRoleId + } +} + +resource contentProcessorAiDeveloperAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorAppName, 'ai-developer') + scope: aiServicesAccount + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: azureAiDeveloperRoleId + } +} + +resource contentProcessorWorkflowAiDeveloperAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorWorkflowName, 'ai-developer') + scope: aiServicesAccount + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: azureAiDeveloperRoleId + } +} + +resource contentProcessorAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorAppName, 'cog-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorApp.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesUserRoleId + } +} + +resource contentProcessorWorkflowAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, contentProcessorWorkflowName, 'cog-user') + scope: aiServicesAccount + properties: { + principalId: contentProcessorWorkflow.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: cognitiveServicesUserRoleId + } +} + +output SOLUTION_NAME string = solutionName +output CONTAINER_WEB_APP_NAME string = contentProcessorWeb.outputs.name +output CONTAINER_API_APP_NAME string = contentProcessorApi.outputs.name +output CONTAINER_WEB_APP_FQDN string = webAppFqdn +output CONTAINER_API_APP_FQDN string = apiAppFqdn +output CONTAINER_APP_NAME string = contentProcessorApp.outputs.name +output CONTAINER_WORKFLOW_APP_NAME string = contentProcessorWorkflow.outputs.name +output CONTAINER_APP_USER_IDENTITY_ID string = managedIdentity.outputs.resourceId +output CONTAINER_APP_USER_PRINCIPAL_ID string = managedIdentity.outputs.principalId +output CONTAINER_REGISTRY_NAME string = containerRegistry.outputs.name +output CONTAINER_REGISTRY_LOGIN_SERVER string = containerRegistry.outputs.loginServer +output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = aiFoundry.outputs.name +output AZURE_RESOURCE_GROUP string = resourceGroup().name diff --git a/infra/bicep/main.json b/infra/bicep/main.json new file mode 100644 index 00000000..53cee80f --- /dev/null +++ b/infra/bicep/main.json @@ -0,0 +1,3406 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6422306545253132015" + }, + "name": "Content Processing Solution Accelerator - Bicep", + "description": "Deploys Content Processing resources using the restored private-repo module interfaces." + }, + "parameters": { + "solutionName": { + "type": "string", + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20 + }, + "location": { + "type": "string", + "metadata": { + "azd": { + "type": "location" + } + } + }, + "azureAiServiceLocation": { + "type": "string", + "metadata": { + "azd": { + "type": "location" + } + } + }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1" + }, + "containerRegistryEndpoint": { + "type": "string", + "defaultValue": "" + }, + "imageTag": { + "type": "string", + "defaultValue": "latest_v2" + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false + }, + "enableScalability": { + "type": "bool", + "defaultValue": false + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false + }, + "tags": { + "type": "object", + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + } + } + }, + "variables": { + "uniqueToken": "[substring(uniqueString(subscription().subscriptionId, resourceGroup().id, parameters('solutionName')), 0, 5)]", + "solutionSuffix": "[toLower(replace(replace(replace(format('{0}{1}', parameters('solutionName'), variables('uniqueToken')), '-', ''), '_', ''), '.', ''))]", + "managedIdentityName": "[format('id-{0}', variables('solutionSuffix'))]", + "containerRegistryName": "[replace(format('cr{0}', variables('solutionSuffix')), '-', '')]", + "storageAccountName": "[take(replace(format('st{0}', variables('solutionSuffix')), '-', ''), 24)]", + "cosmosDbName": "[format('cosmos-{0}', variables('solutionSuffix'))]", + "cosmosDatabaseName": "contentprocessing", + "cosmosContainerName": "documents", + "aiServicesName": "[format('aif-{0}', variables('solutionSuffix'))]", + "aiProjectName": "[format('proj-{0}', variables('solutionSuffix'))]", + "aiSearchName": "[format('srch-{0}', variables('solutionSuffix'))]", + "appConfigurationName": "[format('appcs-{0}', variables('solutionSuffix'))]", + "containerAppEnvironmentName": "[format('cae-{0}', variables('solutionSuffix'))]", + "contentProcessorAppName": "[format('ca-{0}-app', variables('solutionSuffix'))]", + "contentProcessorApiName": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "contentProcessorWebName": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "contentProcessorWorkflowName": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "modelDeploymentName": "[format('gpt-{0}', variables('solutionSuffix'))]", + "storageContainerName": "content", + "storageQueueName": "content", + "acrPullRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "storageBlobDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "storageQueueDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "appConfigurationDataReaderRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "cognitiveServicesOpenAiUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "cognitiveServicesUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "azureAiDeveloperRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "cosmosDbEndpoint": "[format('https://{0}.mongo.cosmos.azure.com:443/', variables('cosmosDbName'))]", + "apiProbes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]" + }, + { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', variables('storageQueueName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageAccountName'), 'default')]" + ] + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2023-04-15", + "name": "[variables('cosmosDbName')]", + "location": "[parameters('location')]", + "kind": "MongoDB", + "tags": "[parameters('tags')]", + "properties": { + "databaseAccountOfferType": "Standard", + "locations": [ + { + "locationName": "[parameters('location')]", + "failoverPriority": 0, + "isZoneRedundant": "[parameters('enableRedundancy')]" + } + ], + "capabilities": [ + { + "name": "EnableMongo" + } + ], + "apiProperties": { + "serverVersion": "7.0" + }, + "disableLocalAuth": false, + "enableAutomaticFailover": false, + "enableMultipleWriteLocations": false, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]" + } + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}', variables('cosmosDbName'), variables('cosmosDatabaseName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosDatabaseName')]" + }, + "options": {} + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]" + ] + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}/{2}', variables('cosmosDbName'), variables('cosmosDatabaseName'), variables('cosmosContainerName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosContainerName')]", + "shardKey": { + "id": "Hash" + }, + "indexes": [ + { + "key": { + "keys": [ + "_id" + ] + } + } + ] + }, + "options": {} + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', variables('cosmosDbName'), variables('cosmosDatabaseName'))]" + ] + }, + { + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', variables('aiServicesName'), variables('aiProjectName'))]", + "location": "[parameters('azureAiServiceLocation')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "tags": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]", + "properties": {} + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', variables('containerRegistryName'))]", + "name": "[guid(variables('containerRegistryName'), variables('managedIdentityName'), 'acr-pull')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('acrPullRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorAppName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorApiName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWebName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWorkflowName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7692694992043508018" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "metadata": { + "description": "SKU name for the workspace." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "retentionInDays": "[parameters('retentionInDays')]", + "sku": { + "name": "[parameters('skuName')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01', 'full').location]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01').customerId]" + } + } + } + } + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "workspaceResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4667471246975862151" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('appi-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace to link to." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Application type." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable IP masking for security." + } + }, + "flowType": { + "type": "string", + "defaultValue": "Bluefield", + "metadata": { + "description": "Flow type for Application Insights." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "web", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "Flow_Type": "[parameters('flowType')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "publicNetworkAccessForIngestion": "Enabled", + "publicNetworkAccessForQuery": "Enabled" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Application Insights instance." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Application Insights instance." + }, + "value": "[parameters('name')]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Instrumentation key for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Connection string for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').ConnectionString]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "Application ID of the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').AppId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[variables('managedIdentityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "14165903959794426055" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the managed identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID (object ID) of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').clientId]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[parameters('identityName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('containerRegistryName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(parameters('enableRedundancy'), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17432455227529690473" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "adminUserEnabled": "[parameters('adminUserEnabled')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "dataEndpointEnabled": false, + "networkRuleBypassOptions": "AzureServices", + "policies": { + "exportPolicy": { + "status": "[parameters('exportPolicyStatus')]" + }, + "retentionPolicy": { + "status": "enabled", + "days": 7 + }, + "trustPolicy": { + "status": "disabled", + "type": "Notary" + } + }, + "zoneRedundancy": "Disabled" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": "[if(parameters('enableRedundancy'), createObject('value', 'Standard_ZRS'), createObject('value', 'Standard_LRS'))]", + "containers": { + "value": [ + { + "name": "[variables('storageContainerName')]", + "publicAccess": "None" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17696053432794478605" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[take(format('st{0}', toLower(replace(parameters('solutionName'), '-', ''))), 24)]", + "metadata": { + "description": "Name of the storage account." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_LRS", + "metadata": { + "description": "Storage account SKU." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "metadata": { + "description": "Storage account kind." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Hot", + "Cool" + ], + "metadata": { + "description": "Access tier." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Allow blob public access." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Allow shared key access." + } + }, + "containers": { + "type": "array", + "defaultValue": [ + { + "name": "default", + "publicAccess": "None" + } + ], + "metadata": { + "description": "Blob containers to create." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "properties": { + "accessTier": "[parameters('accessTier')]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "minimumTlsVersion": "TLS1_2", + "supportsHttpsTrafficOnly": true, + "encryption": { + "services": { + "blob": { + "enabled": true + }, + "file": { + "enabled": true + } + }, + "keySource": "Microsoft.Storage", + "requireInfrastructureEncryption": true + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "blobContainers", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', parameters('containers')[copyIndex()].name)]", + "properties": { + "publicAccess": "[parameters('containers')[copyIndex()].publicAccess]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('name'), 'default')]" + ] + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Storage Account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Storage Account." + }, + "value": "[parameters('name')]" + }, + "blobEndpoint": { + "type": "string", + "metadata": { + "description": "Primary blob endpoint." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.blob]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('aiServicesName')]" + }, + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "principalIds": { + "value": [] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7594344478012985364" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services account." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Required. Azure region for the resource." + } + }, + "principalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether public network access is allowed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to apply to the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "sku": { + "name": "S0" + }, + "properties": { + "customSubDomainName": "[parameters('name')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "disableLocalAuth": true, + "allowProjectManagement": true, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" + } + } + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principalIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", + "properties": { + "principalId": "[parameters('principalIds')[copyIndex()]]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AI Services account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the AI Services account." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the AI Services account." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01').endpoint]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01', 'full').identity.principalId]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-model.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "aiServicesAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "deploymentName": { + "value": "[variables('modelDeploymentName')]" + }, + "modelName": { + "value": "[parameters('gptModelName')]" + }, + "skuName": { + "value": "GlobalStandard" + }, + "skuCapacity": { + "value": 10 + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18411757618261752815" + } + }, + "parameters": { + "aiServicesAccountName": { + "type": "string", + "metadata": { + "description": "Required. Name of the parent AI Services account." + } + }, + "deploymentName": { + "type": "string", + "metadata": { + "description": "Required. Name for this model deployment." + } + }, + "modelFormat": { + "type": "string", + "defaultValue": "OpenAI", + "metadata": { + "description": "Optional. Model format (e.g., OpenAI)." + } + }, + "modelName": { + "type": "string", + "metadata": { + "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." + } + }, + "modelVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Model version. Empty string means latest." + } + }, + "raiPolicyName": { + "type": "string", + "defaultValue": "Microsoft.Default", + "metadata": { + "description": "Optional. RAI policy name." + } + }, + "skuName": { + "type": "string", + "metadata": { + "description": "Required. SKU name (e.g., Standard, GlobalStandard)." + } + }, + "skuCapacity": { + "type": "int", + "metadata": { + "description": "Required. SKU capacity (tokens per minute in thousands)." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", + "properties": { + "model": { + "format": "[parameters('modelFormat')]", + "name": "[parameters('modelName')]", + "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" + }, + "raiPolicyName": "[parameters('raiPolicyName')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacity": "[parameters('skuCapacity')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the deployed model." + }, + "value": "[parameters('deploymentName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the model deployment." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('aiSearchName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "714050788324647491" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "searchServiceUpdate", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "managedIdentityType": { + "value": "[parameters('managedIdentityType')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3683977219901178221" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the existing AI Search service." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The Azure region of the search service." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": { + "type": "[parameters('managedIdentityType')]" + }, + "properties": { + "replicaCount": "[parameters('replicaCount')]", + "partitionCount": "[parameters('partitionCount')]", + "hostingMode": "[parameters('hostingMode')]", + "semanticSearch": "[parameters('semanticSearch')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + } + } + ], + "outputs": { + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the AI Search system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.Search/searchServices', parameters('name')), '2025-05-01', 'full').identity.principalId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + ] + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." + }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'searchServiceUpdate'), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('containerAppEnvironmentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17265155980354931238" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the Container Apps Environment." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + } + }, + "infrastructureSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for VNet integration (optional)." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable zone redundancy." + } + } + }, + "resources": [ + { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "appLogsConfiguration": { + "destination": "log-analytics", + "logAnalyticsConfiguration": { + "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", + "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" + } + }, + "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", + "zoneRedundant": "[parameters('zoneRedundant')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container Apps Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container Apps Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The default domain of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The static IP address of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-config.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('appConfigurationName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName')), '2025-12-01').endpoints['AI Foundry API']]" + }, + { + "name": "APP_COSMOS_DB_ENDPOINT", + "value": "[variables('cosmosDbEndpoint')]" + }, + { + "name": "APP_COSMOS_DB_NAME", + "value": "[variables('cosmosDatabaseName')]" + }, + { + "name": "APP_COSMOS_DB_CONTAINER", + "value": "[variables('cosmosContainerName')]" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "APP_STORAGE_BLOB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.blobEndpoint.value]" + }, + { + "name": "APP_STORAGE_QUEUE_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_STORAGE_CONTAINER_NAME", + "value": "[variables('storageContainerName')]" + }, + { + "name": "APP_AI_SEARCH_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_SEARCH_INDEX", + "value": "content-index" + }, + { + "name": "APP_WORKFLOW_APP_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "APP_API_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18286182317157861590" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the App Configuration store." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Standard" + ], + "metadata": { + "description": "SKU for the configuration store." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Disable local (key-based) authentication." + } + }, + "keyValues": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Key-value pairs to store in the configuration." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2023-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "Enabled" + } + }, + { + "copy": { + "name": "configurationKeyValues", + "count": "[length(parameters('keyValues'))]" + }, + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", + "properties": { + "value": "[parameters('keyValues')[copyIndex()].value]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the App Configuration store." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the App Configuration store." + }, + "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the App Configuration store." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-app.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "disableIngress": { + "value": true + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorAppName')]", + "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]" + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-api.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorApiName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorApiName')]", + "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", + "probes": "[variables('apiProbes')]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-web.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorWebName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWebName')]", + "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "*" + ] + } + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorWorkflowName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWorkflowName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] + } + ], + "outputs": { + "SOLUTION_NAME": { + "type": "string", + "value": "[parameters('solutionName')]" + }, + "CONTAINER_WEB_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_API_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_WEB_APP_FQDN": { + "type": "string", + "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + }, + "CONTAINER_API_APP_FQDN": { + "type": "string", + "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + }, + "CONTAINER_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_WORKFLOW_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/infra/main.bicep b/infra/main.bicep index 9f4ec91e..5e816126 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -1,1860 +1,209 @@ -// ========== main.bicep ========== // +// ============================================================================ +// main.bicep — Deployment Router +// Description: Routes deployment to the appropriate infrastructure flavor. +// - 'bicep' → Vanilla Bicep modules (Docker deployment) +// - 'avm' → AVM-based modules (non-WAF) +// - 'avm-waf' → AVM-based modules with WAF-aligned features +// (monitoring, private networking, scalability, redundancy) +// ============================================================================ targetScope = 'resourceGroup' -metadata name = 'Content Processing Solution Accelerator' -metadata description = 'Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance.' +// ============================================================================ +// Routing Parameter +// ============================================================================ + +@allowed([ + 'bicep' + 'avm' + 'avm-waf' +]) +@description('Required. Deployment flavor: bicep (vanilla Docker), avm (AVM non-WAF), or avm-waf (AVM WAF-aligned).') +param deploymentFlavor string = 'avm' + +// ============================================================================ +// Parameters — Core +// ============================================================================ -// ========== Parameters ========== // @minLength(3) @maxLength(20) -@description('Optional. Name of the solution to deploy. This should be 3-20 characters long.') +@description('Optional. Name of the solution to deploy.') param solutionName string = 'cps' @metadata({ azd: { type: 'location' } }) -@description('Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).') -@allowed([ - 'australiaeast' - 'centralus' - 'eastasia' - 'eastus2' - 'japaneast' - 'northeurope' - 'southeastasia' - 'uksouth' -]) +@description('Required. Azure region for the deployment.') param location string -@minLength(1) -@allowed([ - 'australiaeast' - 'eastus' - 'eastus2' - 'japaneast' - 'southcentralus' - 'southeastasia' - 'swedencentral' - 'uksouth' - 'westeurope' - 'westus' - 'westus3' -]) -@description('Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead.') -@metadata({ - azd: { - type: 'location' - usageName: [ - 'OpenAI.GlobalStandard.gpt-5.1,300' - ] - } -}) +@metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for Azure AI services resources.') param azureAiServiceLocation string -@description('Optional. Type of GPT deployment to use: Standard | GlobalStandard.') -@minLength(1) +// ============================================================================ +// Parameters — AI Configuration +// ============================================================================ + +@description('Optional. Name of the GPT model deployment.') +param gptModelName string = 'gpt-5.1' + @allowed([ 'Standard' 'GlobalStandard' ]) +@description('Optional. Type of GPT deployment: Standard | GlobalStandard.') param deploymentType string = 'GlobalStandard' -@description('Optional. Name of the GPT model to deploy: gpt-5.1') -param gptModelName string = 'gpt-5.1' - -@minLength(1) -@description('Optional. Version of the GPT model to deploy:.') -@allowed([ - '2025-11-13' -]) +@description('Optional. Version of the GPT model.') param gptModelVersion string = '2025-11-13' -@minValue(1) -@description('Optional. Capacity of the GPT deployment: (minimum 10).') +@description('Optional. Capacity (TPM) for the GPT deployment.') param gptDeploymentCapacity int = 300 -@description('Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint).') -param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' +// ============================================================================ +// Parameters — Existing Resources +// ============================================================================ + +@description('Optional. Resource ID of an existing Log Analytics workspace. Leave empty to create a new one.') +param existingLogAnalyticsWorkspaceId string = '' + +@description('Optional. Resource ID of an existing AI Foundry project. Leave empty to create a new one.') +param existingFoundryProjectResourceId string = '' + +// ============================================================================ +// Parameters — Compute +// ============================================================================ + +@description('Optional. Container registry endpoint. Leave empty to use the deployed ACR login server.') +param containerRegistryEndpoint string = '' -@description('Optional. The image tag for the container images.') +@description('Optional. Image tag for all container images.') param imageTag string = 'latest_v2' -@description('Optional. Enable WAF for the deployment.') -param enablePrivateNetworking bool = false +// ============================================================================ +// Parameters — Feature Flags +// ============================================================================ -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true +@description('Optional. Enable private networking.') +param enablePrivateNetworking bool = false -@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') +@description('Optional. Enable monitoring resources.') param enableMonitoring bool = false -@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +@description('Optional. Enable redundancy for supported resources.') param enableRedundancy bool = false -@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +@description('Optional. Enable higher scale defaults for supported resources.') param enableScalability bool = false -@description('Optional. Enable purge protection. Defaults to false.') -param enablePurgeProtection bool = false - -@description('Optional. Tags to be applied to the resources.') -param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} - -@description('Optional: Existing Log Analytics Workspace Resource ID') -param existingLogAnalyticsWorkspaceId string = '' +@description('Optional. Enable AVM telemetry.') +param enableTelemetry bool = true -@description('Use this parameter to use an existing AI project resource ID') -param existingFoundryProjectResourceId string = '' +@description('Optional. Enable purge protection for App Configuration.') +param enablePurgeProtection bool = false -@description('Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true.') -param vmSize string = '' +// ============================================================================ +// Parameters — WAF (AVM-WAF only) +// ============================================================================ -@description('Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') -@secure() +@description('Optional. VM admin username for WAF jumpbox (avm-waf only).') param vmAdminUsername string = '' -@description('Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') @secure() +@description('Optional. VM admin password for WAF jumpbox (avm-waf only).') param vmAdminPassword string = '' -@maxLength(5) -@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') -param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) - -var solutionSuffix = toLower(trim(replace( - replace( - replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), - ' ', - '' - ), - '*', - '' -))) -// ============== // -// Resources // -// ============== // - -var existingProjectResourceId = trim(existingFoundryProjectResourceId) - -// ========== AVM Telemetry ========== // -#disable-next-line no-deployments-resources -resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { - name: take( - '46d3xbcp.ptn.sa-contentprocessing.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', - 64 - ) - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } - } - } - } -} - -// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. -var replicaRegionPairs = { - australiaeast: 'australiasoutheast' - centralus: 'westus' - eastasia: 'japaneast' - eastus: 'centralus' - eastus2: 'centralus' - japaneast: 'eastasia' - northeurope: 'westeurope' - southeastasia: 'eastasia' - uksouth: 'westeurope' - westeurope: 'northeurope' -} -var replicaLocation = replicaRegionPairs[?location] - -// ========== Virtual Network ========== // -module virtualNetwork './modules/virtualNetwork.bicep' = if (enablePrivateNetworking) { - name: take('module.virtual-network.${solutionSuffix}', 64) - params: { - name: 'vnet-${solutionSuffix}' - addressPrefixes: ['10.0.0.0/8'] - location: location - tags: tags - logAnalyticsWorkspaceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - resourceSuffix: solutionSuffix - enableTelemetry: enableTelemetry - } -} - -// Azure Bastion Host -var bastionHostName = 'bas-${solutionSuffix}' -module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePrivateNetworking) { - name: take('avm.res.network.bastion-host.${bastionHostName}', 64) - params: { - name: bastionHostName - skuName: 'Standard' - location: location - virtualNetworkResourceId: virtualNetwork!.outputs.resourceId - diagnosticSettings: enableMonitoring - ? [ - { - name: 'bastionDiagnostics' - workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] - } - ] - : null - tags: tags - enableTelemetry: enableTelemetry - publicIPAddressObject: { - name: 'pip-${bastionHostName}' - } - } -} - -// ========== VM Maintenance Configuration Mapping ========== // +@description('Optional. VM size for WAF jumpbox (avm-waf only).') +param vmSize string = '' -// Jumpbox Virtual Machine -var jumpboxVmName = take('vm-${solutionSuffix}', 15) -module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enablePrivateNetworking) { - name: take('avm.res.compute.virtual-machine.${jumpboxVmName}', 64) - params: { - name: jumpboxVmName - location: location - tags: tags - enableTelemetry: enableTelemetry - computerName: take(jumpboxVmName, 15) - osType: 'Windows' - vmSize: empty(vmSize) ? 'Standard_D2s_v5' : vmSize - adminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername - adminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword - managedIdentities: { - systemAssigned: true - } - patchMode: 'AutomaticByPlatform' - bypassPlatformSafetyChecksOnUserSchedule: true - maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId - enableAutomaticUpdates: true - encryptionAtHost: false - availabilityZone: enableRedundancy ? 1 : -1 - imageReference: { - publisher: 'microsoft-dsvm' - offer: 'dsvm-win-2022' - sku: 'winserver-2022' - version: 'latest' - } - osDisk: { - name: 'osdisk-${jumpboxVmName}' - caching: 'ReadWrite' - createOption: 'FromImage' - deleteOption: 'Delete' - diskSizeGB: 128 - managedDisk: { - // WAF aligned configuration - use Premium storage for better SLA when redundancy is enabled - storageAccountType: enableRedundancy ? 'Premium_LRS' : 'Standard_LRS' - } - } - nicConfigurations: [ - { - name: 'nic-${jumpboxVmName}' - tags: tags - deleteOption: 'Delete' - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring - ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] - : null - ipConfigurations: [ - { - name: '${jumpboxVmName}-nic01-ipconfig01' - subnetResourceId: virtualNetwork!.outputs.adminSubnetResourceId - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring - ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] - : null - } - ] - } - ] - extensionAadJoinConfig: { - enabled: true - tags: tags - typeHandlerVersion: '1.0' - settings: { - mdmId:'' - } - } - extensionAntiMalwareConfig: { - enabled: true - settings: { - AntimalwareEnabled: 'true' - Exclusions: {} - RealtimeProtectionEnabled: 'true' - ScheduledScanSettings: { - day: '7' - isEnabled: 'true' - scanType: 'Quick' - time: '120' - } - } - tags: tags - } - //WAF aligned configuration for Monitoring - extensionMonitoringAgentConfig: enableMonitoring - ? { - dataCollectionRuleAssociations: [ - { - dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId - name: 'send-${logAnalyticsWorkspace!.outputs.name}' - } - ] - enabled: true - tags: tags - } - : null - extensionNetworkWatcherAgentConfig: { - enabled: true - tags: tags - } - } -} +// ============================================================================ +// Parameters — Tags +// ============================================================================ -module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = if (enablePrivateNetworking) { - name: take('avm.res.maintenance-configuration.${jumpboxVmName}', 64) - params: { - name: 'mc-${jumpboxVmName}' - location: location - tags: tags - enableTelemetry: enableTelemetry - extensionProperties: { - InGuestPatchMode: 'User' - } - maintenanceScope: 'InGuestPatch' - maintenanceWindow: { - startDateTime: '2024-06-16 00:00' - duration: '03:55' - timeZone: 'W. Europe Standard Time' - recurEvery: '1Day' - } - visibility: 'Custom' - installPatches: { - rebootSetting: 'IfRequired' - windowsParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } - linuxParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } - } - } +@description('Optional. Tags to be applied to resources.') +param tags object = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location } -var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' -var dataCollectionRulesLocation = logAnalyticsWorkspace!.outputs.location -var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' -var dcrLogAnalyticsDestinationName = 'la-${logAnalyticsWorkspaceResourceName}-destination' -module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.11.0' = if (enablePrivateNetworking && enableMonitoring) { - name: take('avm.res.insights.data-collection-rule.${dataCollectionRulesResourceName}', 64) - params: { - name: dataCollectionRulesResourceName - tags: tags - enableTelemetry: enableTelemetry - location: dataCollectionRulesLocation - dataCollectionRuleProperties: { - kind: 'Windows' - dataSources: { - performanceCounters: [ - { - streams: [ - 'Microsoft-Perf' - ] - samplingFrequencyInSeconds: 60 - counterSpecifiers: [ - '\\Processor Information(_Total)\\% Processor Time' - '\\Processor Information(_Total)\\% Privileged Time' - '\\Processor Information(_Total)\\% User Time' - '\\Processor Information(_Total)\\Processor Frequency' - '\\System\\Processes' - '\\Process(_Total)\\Thread Count' - '\\Process(_Total)\\Handle Count' - '\\System\\System Up Time' - '\\System\\Context Switches/sec' - '\\System\\Processor Queue Length' - '\\Memory\\% Committed Bytes In Use' - '\\Memory\\Available Bytes' - '\\Memory\\Committed Bytes' - '\\Memory\\Cache Bytes' - '\\Memory\\Pool Paged Bytes' - '\\Memory\\Pool Nonpaged Bytes' - '\\Memory\\Pages/sec' - '\\Memory\\Page Faults/sec' - '\\Process(_Total)\\Working Set' - '\\Process(_Total)\\Working Set - Private' - '\\LogicalDisk(_Total)\\% Disk Time' - '\\LogicalDisk(_Total)\\% Disk Read Time' - '\\LogicalDisk(_Total)\\% Disk Write Time' - '\\LogicalDisk(_Total)\\% Idle Time' - '\\LogicalDisk(_Total)\\Disk Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Transfers/sec' - '\\LogicalDisk(_Total)\\Disk Reads/sec' - '\\LogicalDisk(_Total)\\Disk Writes/sec' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' - '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' - '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' - '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' - '\\LogicalDisk(_Total)\\% Free Space' - '\\LogicalDisk(_Total)\\Free Megabytes' - '\\Network Interface(*)\\Bytes Total/sec' - '\\Network Interface(*)\\Bytes Sent/sec' - '\\Network Interface(*)\\Bytes Received/sec' - '\\Network Interface(*)\\Packets/sec' - '\\Network Interface(*)\\Packets Sent/sec' - '\\Network Interface(*)\\Packets Received/sec' - '\\Network Interface(*)\\Packets Outbound Errors' - '\\Network Interface(*)\\Packets Received Errors' - ] - name: 'perfCounterDataSource60' - } - ] - windowsEventLogs: [ - { - name: 'SecurityAuditEvents' - streams: [ - 'Microsoft-Event' - ] - xPathQueries: [ - 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' - ] - } - ] - } - destinations: { - logAnalytics: [ - { - workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId - name: dcrLogAnalyticsDestinationName - } - ] - } - dataFlows: [ - { - streams: [ - 'Microsoft-Perf' - ] - destinations: [ - dcrLogAnalyticsDestinationName - ] - transformKql: 'source' - outputStream: 'Microsoft-Perf' - } - { - streams: [ - 'Microsoft-Event' - ] - destinations: [ - dcrLogAnalyticsDestinationName - ] - transformKql: 'source' - outputStream: 'Microsoft-Event' - } - ] - } - } -} +// ============================================================================ +// Derived Variables +// ============================================================================ -// ========== Private DNS Zones ========== // -var privateDnsZones = [ - 'privatelink.cognitiveservices.azure.com' - 'privatelink.openai.azure.com' - 'privatelink.services.ai.azure.com' - 'privatelink.contentunderstanding.ai.azure.com' - 'privatelink.blob.${environment().suffixes.storage}' - 'privatelink.queue.${environment().suffixes.storage}' - 'privatelink.mongo.cosmos.azure.com' - 'privatelink.azconfig.io' - 'privatelink.azurecr.io' -] +var isAvm = deploymentFlavor == 'avm' || deploymentFlavor == 'avm-waf' +var isBicep = deploymentFlavor == 'bicep' +var useWafDefaults = deploymentFlavor == 'avm-waf' -// DNS Zone Index Constants -var dnsZoneIndex = { - cognitiveServices: 0 - openAI: 1 - aiServices: 2 - contentUnderstanding: 3 - storageBlob: 4 - storageQueue: 5 - cosmosDB: 6 - appConfig: 7 - containerRegistry: 8 -} +var effectiveEnablePrivateNetworking = useWafDefaults ? true : enablePrivateNetworking +var effectiveEnableMonitoring = useWafDefaults ? true : enableMonitoring +var effectiveEnableRedundancy = useWafDefaults ? true : enableRedundancy +var effectiveEnableScalability = useWafDefaults ? true : enableScalability -@batchSize(5) -module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ - for (zone, i) in privateDnsZones: if (enablePrivateNetworking) { - name: take('avm.res.network.private-dns-zone.${split(zone, '.')[1]}', 64) - params: { - name: zone - tags: tags - enableTelemetry: enableTelemetry - virtualNetworkLinks: [{ virtualNetworkResourceId: virtualNetwork!.outputs.resourceId }] - } - } -] +// ============================================================================ +// Module: AVM Deployment +// ============================================================================ -// ========== Log Analytics & Application Insights ========== // -module logAnalyticsWorkspace 'modules/log-analytics-workspace.bicep' = if (enableMonitoring) { - name: take('module.log-analytics-workspace.${solutionSuffix}', 64) +module avmDeployment './avm/main.bicep' = if (isAvm) { + name: take('module.avm.${solutionName}', 64) params: { - name: logAnalyticsWorkspaceResourceName + solutionName: solutionName location: location - tags: tags - enableTelemetry: enableTelemetry + azureAiServiceLocation: azureAiServiceLocation + gptModelName: gptModelName + deploymentType: deploymentType + gptModelVersion: gptModelVersion + gptDeploymentCapacity: gptDeploymentCapacity existingLogAnalyticsWorkspaceId: existingLogAnalyticsWorkspaceId - enablePrivateNetworking: enablePrivateNetworking - enableRedundancy: enableRedundancy - replicaLocation: replicaLocation - } -} - -module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (enableMonitoring) { - name: take('avm.res.insights.component.${solutionSuffix}', 64) - params: { - name: 'appi-${solutionSuffix}' - location: location - enableTelemetry: enableTelemetry - retentionInDays: 365 - kind: 'web' - disableIpMasking: false - flowType: 'Bluefield' - // WAF aligned configuration for Monitoring - workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null - tags: tags - } -} - -@description('Optional. Tag, Created by user name.') -param createdBy string = contains(deployer(), 'userPrincipalName') - ? split(deployer().userPrincipalName, '@')[0] - : deployer().objectId - -// ========== Resource Group Tag ========== // -resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { - name: 'default' - properties: { - tags: { - ...resourceGroup().tags - ...tags - TemplateName: 'Content Processing' - Type: enablePrivateNetworking ? 'WAF' : 'Non-WAF' - CreatedBy: createdBy - DeploymentName: deployment().name - } - } -} - -// ========== Managed Identity ========== // -module avmManagedIdentity './modules/managed-identity.bicep' = { - name: take('module.managed-identity.${solutionSuffix}', 64) - params: { - name: 'id-${solutionSuffix}' - location: location - tags: tags - enableTelemetry: enableTelemetry - } -} - -module avmContainerRegistry 'modules/container-registry.bicep' = { - name: take('module.container-registry.${solutionSuffix}', 64) - params: { - acrName: 'cr${replace(solutionSuffix, '-', '')}' - location: location - acrSku: enableRedundancy || enablePrivateNetworking ? 'Premium' : 'Standard' - publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' - zoneRedundancy: 'Disabled' - roleAssignments: [ - { - principalId: avmContainerRegistryReader.outputs.principalId - roleDefinitionIdOrName: 'AcrPull' - principalType: 'ServicePrincipal' - } - ] - tags: tags + existingFoundryProjectResourceId: existingFoundryProjectResourceId + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enablePrivateNetworking: effectiveEnablePrivateNetworking + enableMonitoring: effectiveEnableMonitoring + enableRedundancy: effectiveEnableRedundancy + enableScalability: effectiveEnableScalability enableTelemetry: enableTelemetry - enableRedundancy: enableRedundancy - replicaLocation: replicaLocation - enablePrivateNetworking: enablePrivateNetworking - backendSubnetResourceId: enablePrivateNetworking ? virtualNetwork!.outputs.backendSubnetResourceId : '' - privateDnsZoneResourceId: enablePrivateNetworking - ? avmPrivateDnsZones[dnsZoneIndex.containerRegistry]!.outputs.resourceId - : '' - } -} - -// // ========== Storage Account ========== // -module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { - name: take('module.storage-account.${solutionSuffix}', 64) - params: { - name: 'st${replace(solutionSuffix, '-', '')}' - location: location - managedIdentities: { systemAssigned: true } - minimumTlsVersion: 'TLS1_2' - enableTelemetry: enableTelemetry - roleAssignments: [ - { - principalId: avmManagedIdentity.outputs.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - ] - networkAcls: { - bypass: 'AzureServices' - defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' - ipRules: [] - } - requireInfrastructureEncryption: true - supportsHttpsTrafficOnly: true - accessTier: 'Hot' - tags: tags - - //<======================= WAF related parameters - allowBlobPublicAccess: false - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - privateEndpoints: (enablePrivateNetworking) - ? [ - { - name: 'pep-blob-${solutionSuffix}' - customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'storage-dns-zone-group-blob' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - service: 'blob' - } - { - name: 'pep-queue-${solutionSuffix}' - customNetworkInterfaceName: 'nic-queue-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'storage-dns-zone-group-queue' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageQueue]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - service: 'queue' - } - ] - : [] - } -} - -// // ========== AI Foundry and related resources ========== // -module avmAiServices 'modules/account/aifoundry.bicep' = { - name: take('module.ai-services.${solutionSuffix}', 64) - params: { - name: 'aif-${solutionSuffix}' - projectName: 'proj-${solutionSuffix}' - projectDescription: 'proj-${solutionSuffix}' - existingFoundryProjectResourceId: existingProjectResourceId - location: azureAiServiceLocation - sku: 'S0' - allowProjectManagement: true - managedIdentities: { systemAssigned: true } - kind: 'AIServices' - tags: { - app: solutionSuffix - location: azureAiServiceLocation - } - customSubDomainName: 'aif-${solutionSuffix}' - diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null - roleAssignments: [ - { - principalId: avmManagedIdentity.outputs.principalId - roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Azure AI Developer' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Azure AI Developer' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services User' - principalType: 'ServicePrincipal' - } - ] - networkAcls: { - bypass: 'AzureServices' - defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' - } - disableLocalAuth: true - enableTelemetry: enableTelemetry - deployments: [ - { - name: gptModelName - model: { - format: 'OpenAI' - name: gptModelName - version: gptModelVersion - } - sku: { - name: deploymentType - capacity: gptDeploymentCapacity - } - raiPolicyName: 'Microsoft.Default' - } - ] - - // WAF related parameters - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - //publicNetworkAccess: 'Enabled' // Always enabled for AI Services - } -} - -module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking && empty(existingProjectResourceId)) { - name: take('avm.res.network.private-endpoint.${solutionSuffix}', 64) - params: { - name: 'pep-aiservices-${solutionSuffix}' - location: location - tags: tags - customNetworkInterfaceName: 'nic-aiservices-${solutionSuffix}' - privateLinkServiceConnections: [ - { - name: 'pep-aiservices-${solutionSuffix}-cognitiveservices-connection' - properties: { - privateLinkServiceId: avmAiServices.outputs.resourceId - groupIds: ['account'] - } - } - ] - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'ai-services-dns-zone-cognitiveservices' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId - } - { - name: 'ai-services-dns-zone-openai' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId - } - { - name: 'ai-services-dns-zone-aiservices' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId - } - { - name: 'ai-services-dns-zone-contentunderstanding' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId - } -} - -// ========== Container App Environment ========== // -module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { - name: take('avm.res.app.managed-environment.${solutionSuffix}', 64) - params: { - name: 'cae-${solutionSuffix}' - location: location - tags: { - ...resourceGroup().tags - ...tags - } - managedIdentities: { systemAssigned: true } - appLogsConfiguration: enableMonitoring - ? { - destination: 'log-analytics' - logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId - } - : null - workloadProfiles: [ - { - name: 'Consumption' - workloadProfileType: 'Consumption' - } - ] - enableTelemetry: enableTelemetry - publicNetworkAccess: 'Enabled' // Always enabled for Container Apps Environment - - // <========== WAF related parameters - - platformReservedCidr: '172.17.17.0/24' - platformReservedDnsIP: '172.17.17.17' - zoneRedundant: (enablePrivateNetworking) ? true : false // Enable zone redundancy if private networking is enabled - infrastructureSubnetResourceId: (enablePrivateNetworking) - ? virtualNetwork!.outputs.containersSubnetResourceId // Use the container app subnet - : null // Use the container app subnet - } -} - -// //=========== Managed Identity for Container Registry ========== // -module avmContainerRegistryReader 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { - name: take('avm.res.managed-identity.user-assigned-identity.${solutionSuffix}', 64) - params: { - name: 'id-acr-${solutionSuffix}' - location: location - tags: tags - enableTelemetry: enableTelemetry - } -} - -// ========== Container App ========== // -module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-app' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - - containers: [ - { - name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessor' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } - tags: tags - } -} - -// ========== Container App API ========== // -module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-api.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-api' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorAPI' - } - ] - probes: [ - // Liveness Probe - Checks if the app is still running - { - type: 'Liveness' - httpGet: { - path: '/startup' // Your app must expose this endpoint - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - // Readiness Probe - Checks if the app is ready to receive traffic - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 // Wait 10s before checking - periodSeconds: 5 // Check every 15s - failureThreshold: 10 // Restart if it fails 5 times - } - ] - } - ] - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - ingressExternal: true - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - corsPolicy: { - allowedOrigins: [ - '*' - ] - allowedMethods: [ - 'GET' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - ] - allowedHeaders: [ - 'Authorization' - 'Content-Type' - '*' - ] - } - } -} - -//========== Container App Web ========== // -module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-web.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-web' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - ingressExternal: true - ingressTargetPort: 3000 - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-web' - image: '${containerRegistryEndpoint}/contentprocessorweb:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_API_BASE_URL' - value: 'https://${avmContainerApp_API.outputs.fqdn}' - } - { - name: 'APP_WEB_CLIENT_ID' - value: '' - } - { - name: 'APP_WEB_AUTHORITY' - value: '${environment().authentication.loginEndpoint}/${tenant().tenantId}' - } - { - name: 'APP_WEB_SCOPE' - value: '' - } - { - name: 'APP_API_SCOPE' - value: '' - } - { - name: 'APP_REDIRECT_URL' - value: '/' - } - { - name: 'APP_POST_REDIRECT_URL' - value: '/' - } - { - name: 'APP_CONSOLE_LOG_ENABLED' - value: 'false' - } - ] - } - ] - } -} - -// ========== Container App Workflow ========== // -module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-wkfl.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-wkfl' - location: location - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorWorkflow' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } - } -} - -// ========== Cosmos Database for Mongo DB ========== // -module avmCosmosDB 'br/public:avm/res/document-db/database-account:0.19.0' = { - name: take('avm.res.document-db.database-account.${solutionSuffix}', 64) - params: { - name: 'cosmos-${solutionSuffix}' - location: location - mongodbDatabases: [ - { - name: 'default' - tag: 'default database' - } - ] - tags: tags - enableTelemetry: enableTelemetry - databaseAccountOfferType: 'Standard' - enableAutomaticFailover: false - serverVersion: '7.0' - capabilitiesToAdd: [ - 'EnableMongo' - ] - defaultConsistencyLevel: 'Session' - maxIntervalInSeconds: 5 - maxStalenessPrefix: 100 - zoneRedundant: false - - // WAF related parameters - networkRestrictions: { - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - ipRules: [] - virtualNetworkRules: [] - } - - privateEndpoints: (enablePrivateNetworking) - ? [ - { - name: 'pep-cosmosdb-${solutionSuffix}' - customNetworkInterfaceName: 'nic-cosmosdb-${solutionSuffix}' - privateEndpointResourceId: virtualNetwork!.outputs.resourceId - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'cosmosdb-dns-zone-group' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId - } - ] - } - service: 'MongoDB' - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - } - ] - : [] - } -} - -// ========== App Configuration ========== // -module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { - name: take('avm.res.app.configuration-store.${solutionSuffix}', 64) - params: { - name: 'appcs-${solutionSuffix}' - location: location - enablePurgeProtection: enablePurgeProtection - tags: { - app: solutionSuffix - location: location - } - enableTelemetry: enableTelemetry - managedIdentities: { systemAssigned: true } - sku: 'Standard' - diagnosticSettings: enableMonitoring - ? [ - { - workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] - } - ] - : null - disableLocalAuth: false - replicaLocations: enableRedundancy? [{ replicaLocation: replicaLocation }] : [] - roleAssignments: [ - { - principalId: avmContainerApp.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_API.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Web.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - ] - keyValues: [ - { - name: 'APP_AZURE_OPENAI_ENDPOINT' - value: avmAiServices.outputs.endpoint //TODO: replace with actual endpoint - } - { - name: 'APP_AZURE_OPENAI_MODEL' - value: gptModelName - } - { - name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - { - name: 'APP_COSMOS_CONTAINER_PROCESS' - value: 'Processes' - } - { - name: 'APP_COSMOS_CONTAINER_SCHEMA' - value: 'Schemas' - } - { - name: 'APP_COSMOS_DATABASE' - value: 'ContentProcess' - } - { - name: 'APP_CPS_CONFIGURATION' - value: 'cps-configuration' - } - { - name: 'APP_CPS_MAX_FILESIZE_MB' - value: '20' - } - { - name: 'APP_CPS_PROCESSES' - value: 'cps-processes' - } - { - name: 'APP_MESSAGE_QUEUE_EXTRACT' - value: 'content-pipeline-extract-queue' - } - { - name: 'APP_MESSAGE_QUEUE_INTERVAL' - value: '5' - } - { - name: 'APP_MESSAGE_QUEUE_PROCESS_TIMEOUT' - value: '180' - } - { - name: 'APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT' - value: '10' - } - { - name: 'APP_PROCESS_STEPS' - value: 'extract,map,evaluate,save' - } - { - name: 'APP_STORAGE_BLOB_URL' - value: avmStorageAccount.outputs.serviceEndpoints.blob - } - { - name: 'APP_STORAGE_QUEUE_URL' - value: avmStorageAccount.outputs.serviceEndpoints.queue - } - { - name: 'APP_AI_PROJECT_ENDPOINT' - value: avmAiServices.outputs.aiProjectInfo.?apiEndpoint ?? '' - } - { - name: 'APP_COSMOS_CONNSTR' - value: avmCosmosDB.outputs.primaryReadWriteConnectionString - } - // ===== v2 Workflow Keys ===== // - { - name: 'APP_COSMOS_CONTAINER_BATCH_PROCESS' - value: 'claimprocesses' - } - { - name: 'APP_COSMOS_CONTAINER_BATCHES' - value: 'batches' - } - { - name: 'APP_COSMOS_CONTAINER_SCHEMASET' - value: 'Schemasets' - } - { - name: 'APP_CPS_PROCESS_BATCH' - value: 'process-batch' - } - { - name: 'APP_CPS_CONTENT_PROCESS_ENDPOINT' - value: 'http://${avmContainerApp_API.outputs.name}/' - } - { - name: 'APP_CPS_POLL_INTERVAL_SECONDS' - value: '3' - } - { - name: 'APP_STORAGE_ACCOUNT_NAME' - value: avmStorageAccount.outputs.name - } - { - name: 'CLAIM_PROCESS_QUEUE_NAME' - value: 'claim-process-queue' - } - { - name: 'DEAD_LETTER_QUEUE_NAME' - value: 'claim-process-dead-letter-queue' - } - { - name: 'AZURE_OPENAI_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - { - name: 'AZURE_OPENAI_CHAT_DEPLOYMENT_NAME' - value: gptModelName - } - { - name: 'AZURE_OPENAI_API_VERSION' - value: '2025-03-01-preview' - } - { - name: 'AZURE_OPENAI_ENDPOINT_BASE' - value: avmAiServices.outputs.endpoint - } - // ===== Agent Framework Keys ===== // - { - name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' - value: '' - } - { - name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' - value: '' - } - { - name: 'AZURE_TRACING_ENABLED' - value: 'True' - } - { - name: 'GLOBAL_LLM_SERVICE' - value: 'AzureOpenAI' - } - // ===== GPT-5 Service Prefix Keys ===== // - { - name: 'GPT5_API_VERSION' - value: '2025-03-01-preview' - } - { - name: 'GPT5_CHAT_DEPLOYMENT_NAME' - value: 'gpt-5' - } - { - name: 'GPT5_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - // ===== PHI-4 Service Prefix Keys ===== // - { - name: 'PHI4_API_VERSION' - value: '2024-05-01-preview' - } - { - name: 'PHI4_CHAT_DEPLOYMENT_NAME' - value: 'phi-4' - } - { - name: 'PHI4_ENDPOINT' - value: avmAiServices.outputs.endpoint - } - ] - - publicNetworkAccess: 'Enabled' - } -} - -module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = if (enablePrivateNetworking) { - name: take('avm.res.app.configuration-store.update.${solutionSuffix}', 64) - params: { - name: 'appcs-${solutionSuffix}' - location: location enablePurgeProtection: enablePurgeProtection - enableTelemetry: enableTelemetry + vmAdminUsername: vmAdminUsername + vmAdminPassword: vmAdminPassword + vmSize: vmSize tags: tags - publicNetworkAccess: 'Disabled' - privateEndpoints: [ - { - name: 'pep-appconfig-${solutionSuffix}' - customNetworkInterfaceName: 'nic-appconfig-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'appconfig-dns-zone-group' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.appConfig]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - } - ] } - - dependsOn: [ - avmAppConfig - ] } -// ========== Container App Update Modules ========== // -module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-update.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-app' - location: location - enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessor' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: enableScalability - ? [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: 100 - } - } - } - ] - : [] - } - } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] -} +// ============================================================================ +// Module: Vanilla Bicep Deployment +// ============================================================================ -module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) +module bicepDeployment './bicep/main.bicep' = if (isBicep) { + name: take('module.bicep.${solutionName}', 64) params: { - name: 'ca-${solutionSuffix}-api' + solutionName: solutionName location: location + azureAiServiceLocation: azureAiServiceLocation + gptModelName: gptModelName + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enablePrivateNetworking: effectiveEnablePrivateNetworking + enableMonitoring: effectiveEnableMonitoring + enableRedundancy: effectiveEnableRedundancy + enableScalability: effectiveEnableScalability enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - - containers: [ - { - name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorAPI' - } - ] - probes: [ - // Liveness Probe - Checks if the app is still running - { - type: 'Liveness' - httpGet: { - path: '/startup' // Your app must expose this endpoint - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - // Readiness Probe - Checks if the app is ready to receive traffic - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 // Wait 10s before checking - periodSeconds: 5 // Check every 15s - failureThreshold: 10 // Restart if it fails 5 times - } - ] - } - ] - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - ingressExternal: true - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - corsPolicy: { - allowedOrigins: [ - '*' - ] - allowedMethods: [ - 'GET' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - ] - allowedHeaders: [ - 'Authorization' - 'Content-Type' - '*' - ] - } - } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] -} - -// ========== Container App Workflow Update ========== // -module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-wkfl' - location: location - enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null + enablePurgeProtection: enablePurgeProtection tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorWorkflow' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } } } -// ============ // -// Outputs // -// ============ // - -@description('The name of the Container App used for Web App.') -output CONTAINER_WEB_APP_NAME string = avmContainerApp_Web.outputs.name - -@description('The name of the Container App used for API.') -output CONTAINER_API_APP_NAME string = avmContainerApp_API.outputs.name - -@description('The FQDN of the Container App.') -output CONTAINER_WEB_APP_FQDN string = avmContainerApp_Web.outputs.fqdn - -@description('The FQDN of the Container App API.') -output CONTAINER_API_APP_FQDN string = avmContainerApp_API.outputs.fqdn - -@description('The name of the Container App used for APP.') -output CONTAINER_APP_NAME string = avmContainerApp.outputs.name - -@description('The name of the Container App used for Workflow.') -output CONTAINER_WORKFLOW_APP_NAME string = avmContainerApp_Workflow.outputs.name - -@description('The user identity resource ID used fot the Container APP.') -output CONTAINER_APP_USER_IDENTITY_ID string = avmContainerRegistryReader.outputs.resourceId - -@description('The user identity Principal ID used fot the Container APP.') -output CONTAINER_APP_USER_PRINCIPAL_ID string = avmContainerRegistryReader.outputs.principalId - -@description('The name of the Azure Container Registry.') -output CONTAINER_REGISTRY_NAME string = avmContainerRegistry.outputs.name - -@description('The login server of the Azure Container Registry.') -output CONTAINER_REGISTRY_LOGIN_SERVER string = avmContainerRegistry.outputs.loginServer - -@description('The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA.') -output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices.outputs.name +// ============================================================================ +// Outputs — Coalesced from whichever flavor was deployed +// ============================================================================ -@description('The resource group the resources were deployed into.') -output AZURE_RESOURCE_GROUP string = resourceGroup().name +output SOLUTION_NAME string = isAvm ? avmDeployment!.outputs.SOLUTION_NAME : bicepDeployment!.outputs.SOLUTION_NAME +output CONTAINER_WEB_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_WEB_APP_NAME : bicepDeployment!.outputs.CONTAINER_WEB_APP_NAME +output CONTAINER_API_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_API_APP_NAME : bicepDeployment!.outputs.CONTAINER_API_APP_NAME +output CONTAINER_WEB_APP_FQDN string = isAvm ? avmDeployment!.outputs.CONTAINER_WEB_APP_FQDN : bicepDeployment!.outputs.CONTAINER_WEB_APP_FQDN +output CONTAINER_API_APP_FQDN string = isAvm ? avmDeployment!.outputs.CONTAINER_API_APP_FQDN : bicepDeployment!.outputs.CONTAINER_API_APP_FQDN +output CONTAINER_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_NAME : bicepDeployment!.outputs.CONTAINER_APP_NAME +output CONTAINER_WORKFLOW_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_WORKFLOW_APP_NAME : bicepDeployment!.outputs.CONTAINER_WORKFLOW_APP_NAME +output CONTAINER_APP_USER_IDENTITY_ID string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_USER_IDENTITY_ID : bicepDeployment!.outputs.CONTAINER_APP_USER_IDENTITY_ID +output CONTAINER_APP_USER_PRINCIPAL_ID string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_USER_PRINCIPAL_ID : bicepDeployment!.outputs.CONTAINER_APP_USER_PRINCIPAL_ID +output CONTAINER_REGISTRY_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_REGISTRY_NAME : bicepDeployment!.outputs.CONTAINER_REGISTRY_NAME +output CONTAINER_REGISTRY_LOGIN_SERVER string = isAvm ? avmDeployment!.outputs.CONTAINER_REGISTRY_LOGIN_SERVER : bicepDeployment!.outputs.CONTAINER_REGISTRY_LOGIN_SERVER +output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = isAvm ? avmDeployment!.outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME : bicepDeployment!.outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME +output AZURE_RESOURCE_GROUP string = isAvm ? avmDeployment!.outputs.AZURE_RESOURCE_GROUP : bicepDeployment!.outputs.AZURE_RESOURCE_GROUP diff --git a/infra/main.json b/infra/main.json index 7aa9114e..fbefa771 100644 --- a/infra/main.json +++ b/infra/main.json @@ -1,70 +1,59 @@ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "12545195410241248179" - }, - "name": "Content Processing Solution Accelerator", - "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." + "version": "0.42.1.51946", + "templateHash": "15979971030931723082" + } }, "parameters": { + "deploymentFlavor": { + "type": "string", + "defaultValue": "avm", + "allowedValues": [ + "bicep", + "avm", + "avm-waf" + ], + "metadata": { + "description": "Required. Deployment flavor: bicep (vanilla Docker), avm (AVM non-WAF), or avm-waf (AVM WAF-aligned)." + } + }, "solutionName": { "type": "string", "defaultValue": "cps", "minLength": 3, "maxLength": 20, "metadata": { - "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." + "description": "Optional. Name of the solution to deploy." } }, "location": { "type": "string", - "allowedValues": [ - "australiaeast", - "centralus", - "eastasia", - "eastus2", - "japaneast", - "northeurope", - "southeastasia", - "uksouth" - ], "metadata": { "azd": { "type": "location" }, - "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." + "description": "Required. Azure region for the deployment." } }, "azureAiServiceLocation": { "type": "string", - "allowedValues": [ - "australiaeast", - "eastus", - "eastus2", - "japaneast", - "southcentralus", - "southeastasia", - "swedencentral", - "uksouth", - "westeurope", - "westus", - "westus3" - ], "metadata": { "azd": { - "type": "location", - "usageName": [ - "OpenAI.GlobalStandard.gpt-5.1,300" - ] + "type": "location" }, - "description": "Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead." - }, - "minLength": 1 + "description": "Required. Azure region for Azure AI services resources." + } + }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1", + "metadata": { + "description": "Optional. Name of the GPT model deployment." + } }, "deploymentType": { "type": "string", @@ -73,261 +62,209 @@ "Standard", "GlobalStandard" ], - "minLength": 1, - "metadata": { - "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." - } - }, - "gptModelName": { - "type": "string", - "defaultValue": "gpt-5.1", "metadata": { - "description": "Optional. Name of the GPT model to deploy: gpt-5.1" + "description": "Optional. Type of GPT deployment: Standard | GlobalStandard." } }, "gptModelVersion": { "type": "string", "defaultValue": "2025-11-13", - "allowedValues": [ - "2025-11-13" - ], - "minLength": 1, "metadata": { - "description": "Optional. Version of the GPT model to deploy:." + "description": "Optional. Version of the GPT model." } }, "gptDeploymentCapacity": { "type": "int", "defaultValue": 300, - "minValue": 1, "metadata": { - "description": "Optional. Capacity of the GPT deployment: (minimum 10)." + "description": "Optional. Capacity (TPM) for the GPT deployment." + } + }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an existing Log Analytics workspace. Leave empty to create a new one." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an existing AI Foundry project. Leave empty to create a new one." } }, "containerRegistryEndpoint": { "type": "string", - "defaultValue": "cpscontainerreg.azurecr.io", + "defaultValue": "", "metadata": { - "description": "Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint)." + "description": "Optional. Container registry endpoint. Leave empty to use the deployed ACR login server." } }, "imageTag": { "type": "string", "defaultValue": "latest_v2", "metadata": { - "description": "Optional. The image tag for the container images." + "description": "Optional. Image tag for all container images." } }, "enablePrivateNetworking": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable WAF for the deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Enable private networking." } }, "enableMonitoring": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + "description": "Optional. Enable monitoring resources." } }, "enableRedundancy": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + "description": "Optional. Enable redundancy for supported resources." } }, "enableScalability": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + "description": "Optional. Enable higher scale defaults for supported resources." } }, - "enablePurgeProtection": { + "enableTelemetry": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable purge protection. Defaults to false." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" - }, - "description": "Optional. Tags to be applied to the resources." - }, - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - } - }, - "existingLogAnalyticsWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Existing Log Analytics Workspace Resource ID" - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "", + "defaultValue": true, "metadata": { - "description": "Use this parameter to use an existing AI project resource ID" + "description": "Optional. Enable AVM telemetry." } }, - "vmSize": { - "type": "string", - "defaultValue": "", + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + "description": "Optional. Enable purge protection for App Configuration." } }, "vmAdminUsername": { - "type": "securestring", + "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + "description": "Optional. VM admin username for WAF jumpbox (avm-waf only)." } }, "vmAdminPassword": { "type": "securestring", "defaultValue": "", "metadata": { - "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + "description": "Optional. VM admin password for WAF jumpbox (avm-waf only)." } }, - "solutionUniqueText": { + "vmSize": { "type": "string", - "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", - "maxLength": 5, + "defaultValue": "", "metadata": { - "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." + "description": "Optional. VM size for WAF jumpbox (avm-waf only)." } }, - "createdBy": { - "type": "string", - "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", + "tags": { + "type": "object", + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + }, "metadata": { - "description": "Optional. Tag, Created by user name." + "description": "Optional. Tags to be applied to resources." } } }, "variables": { - "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", - "existingProjectResourceId": "[trim(parameters('existingFoundryProjectResourceId'))]", - "replicaRegionPairs": { - "australiaeast": "australiasoutheast", - "centralus": "westus", - "eastasia": "japaneast", - "eastus": "centralus", - "eastus2": "centralus", - "japaneast": "eastasia", - "northeurope": "westeurope", - "southeastasia": "eastasia", - "uksouth": "westeurope", - "westeurope": "northeurope" - }, - "replicaLocation": "[tryGet(variables('replicaRegionPairs'), parameters('location'))]", - "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", - "jumpboxVmName": "[take(format('vm-{0}', variables('solutionSuffix')), 15)]", - "dataCollectionRulesResourceName": "[format('dcr-{0}', variables('solutionSuffix'))]", - "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", - "dcrLogAnalyticsDestinationName": "[format('la-{0}-destination', variables('logAnalyticsWorkspaceResourceName'))]", - "privateDnsZones": [ - "privatelink.cognitiveservices.azure.com", - "privatelink.openai.azure.com", - "privatelink.services.ai.azure.com", - "privatelink.contentunderstanding.ai.azure.com", - "[format('privatelink.blob.{0}', environment().suffixes.storage)]", - "[format('privatelink.queue.{0}', environment().suffixes.storage)]", - "privatelink.mongo.cosmos.azure.com", - "privatelink.azconfig.io", - "privatelink.azurecr.io" - ], - "dnsZoneIndex": { - "cognitiveServices": 0, - "openAI": 1, - "aiServices": 2, - "contentUnderstanding": 3, - "storageBlob": 4, - "storageQueue": 5, - "cosmosDB": 6, - "appConfig": 7, - "containerRegistry": 8 - } + "isAvm": "[or(equals(parameters('deploymentFlavor'), 'avm'), equals(parameters('deploymentFlavor'), 'avm-waf'))]", + "isBicep": "[equals(parameters('deploymentFlavor'), 'bicep')]", + "useWafDefaults": "[equals(parameters('deploymentFlavor'), 'avm-waf')]", + "effectiveEnablePrivateNetworking": "[if(variables('useWafDefaults'), true(), parameters('enablePrivateNetworking'))]", + "effectiveEnableMonitoring": "[if(variables('useWafDefaults'), true(), parameters('enableMonitoring'))]", + "effectiveEnableRedundancy": "[if(variables('useWafDefaults'), true(), parameters('enableRedundancy'))]", + "effectiveEnableScalability": "[if(variables('useWafDefaults'), true(), parameters('enableScalability'))]" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('46d3xbcp.ptn.sa-contentprocessing.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "resourceGroupTags": { - "type": "Microsoft.Resources/tags", - "apiVersion": "2025-04-01", - "name": "default", - "properties": { - "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" - } - }, - "virtualNetwork": { - "condition": "[parameters('enablePrivateNetworking')]", + "resources": [ + { + "condition": "[variables('isAvm')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.avm.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('vnet-{0}', variables('solutionSuffix'))]" - }, - "addressPrefixes": { - "value": [ - "10.0.0.0/8" - ] + "solutionName": { + "value": "[parameters('solutionName')]" }, "location": { "value": "[parameters('location')]" }, - "tags": { - "value": "[parameters('tags')]" + "azureAiServiceLocation": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "gptModelName": { + "value": "[parameters('gptModelName')]" + }, + "deploymentType": { + "value": "[parameters('deploymentType')]" + }, + "gptModelVersion": { + "value": "[parameters('gptModelVersion')]" + }, + "gptDeploymentCapacity": { + "value": "[parameters('gptDeploymentCapacity')]" + }, + "existingLogAnalyticsWorkspaceId": { + "value": "[parameters('existingLogAnalyticsWorkspaceId')]" + }, + "existingFoundryProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enablePrivateNetworking": { + "value": "[variables('effectiveEnablePrivateNetworking')]" }, - "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "resourceSuffix": { - "value": "[variables('solutionSuffix')]" + "enableMonitoring": { + "value": "[variables('effectiveEnableMonitoring')]" + }, + "enableRedundancy": { + "value": "[variables('effectiveEnableRedundancy')]" + }, + "enableScalability": { + "value": "[variables('effectiveEnableScalability')]" }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "vmAdminUsername": { + "value": "[parameters('vmAdminUsername')]" + }, + "vmAdminPassword": { + "value": "[parameters('vmAdminPassword')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -337,470 +274,327 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "13206959925771644022" - } + "version": "0.42.1.51946", + "templateHash": "12171467271723171429" + }, + "name": "Content Processing Solution Accelerator", + "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." }, - "definitions": { - "subnetOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the subnet." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the subnet." - } - }, - "nsgName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The name of the associated network security group, if any." - } - }, - "nsgResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The resource ID of the associated network security group, if any." - } - } - }, + "parameters": { + "solutionName": { + "type": "string", + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20, "metadata": { - "__bicep_export!": true, - "description": "Custom type definition for subnet resource information as output" + "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." } }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. Prefixes for the subnet." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable apply network policies on private link service in the subnet." - } - }, - "networkSecurityGroup": { - "$ref": "#/definitions/networkSecurityGroupType", - "nullable": true, - "metadata": { - "description": "Optional. Network Security Group configuration for the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of service endpoint policies." - } + "location": { + "type": "string", + "allowedValues": [ + "australiaeast", + "centralus", + "eastasia", + "eastus2", + "japaneast", + "northeurope", + "southeastasia", + "uksouth" + ], + "metadata": { + "azd": { + "type": "location" }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } + "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." + } + }, + "azureAiServiceLocation": { + "type": "string", + "allowedValues": [ + "australiaeast", + "eastus", + "eastus2", + "japaneast", + "southcentralus", + "southeastasia", + "swedencentral", + "uksouth", + "westeurope", + "westus", + "westus3" + ], + "metadata": { + "azd": { + "type": "location", + "usageName": [ + "OpenAI.GlobalStandard.gpt-5.1,300" + ] }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - } + "description": "Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead." }, + "minLength": 1 + }, + "deploymentType": { + "type": "string", + "defaultValue": "GlobalStandard", + "allowedValues": [ + "Standard", + "GlobalStandard" + ], + "minLength": 1, "metadata": { - "__bicep_export!": true, - "description": "Custom type definition for subnet configuration" + "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." } }, - "networkSecurityGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network security group." - } - }, - "securityRules": { - "type": "array", - "items": { - "type": "object" - }, - "metadata": { - "description": "Required. The security rules for the network security group." - } - } - }, + "gptModelName": { + "type": "string", + "defaultValue": "gpt-5.1", "metadata": { - "__bicep_export!": true, - "description": "Custom type definition for network security group configuration" + "description": "Optional. Name of the GPT model to deploy: gpt-5.1" } - } - }, - "parameters": { - "name": { + }, + "gptModelVersion": { "type": "string", + "defaultValue": "2025-11-13", + "allowedValues": [ + "2025-11-13" + ], + "minLength": 1, "metadata": { - "description": "Required. Name of the virtual network." + "description": "Optional. Version of the GPT model to deploy:." } }, - "location": { + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": 300, + "minValue": 1, + "metadata": { + "description": "Optional. Capacity of the GPT deployment: (minimum 10)." + } + }, + "containerRegistryEndpoint": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "cpscontainerreg.azurecr.io", "metadata": { - "description": "Optional. Azure region to deploy resources." + "description": "Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint)." } }, - "addressPrefixes": { - "type": "array", + "imageTag": { + "type": "string", + "defaultValue": "latest_v2", "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + "description": "Optional. The image tag for the container images." } }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "defaultValue": [ - { - "name": "containers", - "addressPrefixes": [ - "10.0.2.0/24" - ], - "delegation": "Microsoft.App/environments", - "networkSecurityGroup": { - "name": "nsg-containers", - "securityRules": [ - { - "name": "AllowHttpsInbound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 100, - "protocol": "Tcp", - "sourceAddressPrefix": "Internet", - "sourcePortRange": "*", - "destinationPortRanges": [ - "443", - "80" - ], - "destinationAddressPrefixes": [ - "10.0.2.0/24" - ] - } - }, - { - "name": "AllowAzureLoadBalancerInbound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 102, - "protocol": "*", - "sourceAddressPrefix": "AzureLoadBalancer", - "sourcePortRange": "*", - "destinationPortRanges": [ - "30000-32767" - ], - "destinationAddressPrefixes": [ - "10.0.2.0/24" - ] - } - }, - { - "name": "AllowSideCarsInbound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 103, - "protocol": "*", - "sourcePortRange": "*", - "sourceAddressPrefixes": [ - "10.0.2.0/24" - ], - "destinationPortRange": "*", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowOutboundToAzureServices", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 200, - "protocol": "*", - "sourceAddressPrefixes": [ - "10.0.2.0/24" - ], - "sourcePortRange": "*", - "destinationPortRange": "*", - "destinationAddressPrefix": "*" - } - }, - { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "direction": "Outbound", - "priority": 100, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "3389", - "22" - ], - "sourceAddressPrefix": "VirtualNetwork", - "destinationAddressPrefix": "*" - } - } - ] - } - }, - { - "name": "backend", - "addressPrefixes": [ - "10.0.0.0/24" - ], - "privateEndpointNetworkPolicies": "Disabled", - "privateLinkServiceNetworkPolicies": "Disabled", - "networkSecurityGroup": { - "name": "nsg-backend", - "securityRules": [ - { - "name": "Deny-hop-outbound", - "properties": { - "access": "Deny", - "direction": "Outbound", - "priority": 200, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "3389", - "22" - ], - "sourceAddressPrefix": "VirtualNetwork", - "destinationAddressPrefix": "*" - } - } - ] - } - }, - { - "name": "AzureBastionSubnet", - "addressPrefixes": [ - "10.0.1.32/27" - ], - "networkSecurityGroup": { - "name": "nsg-bastion", - "securityRules": [ - { - "name": "AllowGatewayManager", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2702, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "GatewayManager", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowHttpsInBound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2703, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "Internet", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowSshRdpOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 100, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AllowAzureCloudOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 110, - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "AzureCloud" - } - } - ] - } - }, - { - "name": "admin", - "addressPrefixes": [ - "10.0.1.0/27" - ], - "networkSecurityGroup": { - "name": "nsg-admin", - "securityRules": [ - { - "name": "Deny-hop-outbound", - "properties": { - "access": "Deny", - "direction": "Outbound", - "priority": 200, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "3389", - "22" - ], - "sourceAddressPrefix": "VirtualNetwork", - "destinationAddressPrefix": "*" - } - } - ] - } - } - ], + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable WAF for the deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + } + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enableScalability": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. An array of subnets to be created within the virtual network. Each subnet can have its own configuration and associated Network Security Group (NSG)." + "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable purge protection. Defaults to false." } }, "tags": { "type": "object", - "defaultValue": {}, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" + }, "description": "Optional. Tags to be applied to the resources." + }, + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + } + }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Existing Log Analytics Workspace Resource ID" } }, - "logAnalyticsWorkspaceId": { + "existingFoundryProjectResourceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The resource ID of the Log Analytics Workspace to send diagnostic logs to." + "description": "Use this parameter to use an existing AI project resource ID" } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "vmSize": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminUsername": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." } }, - "resourceSuffix": { + "createdBy": { "type": "string", + "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", "metadata": { - "description": "Required. Suffix for resource naming." + "description": "Optional. Tag, Created by user name." } } }, + "variables": { + "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", + "existingProjectResourceId": "[trim(parameters('existingFoundryProjectResourceId'))]", + "replicaRegionPairs": { + "australiaeast": "australiasoutheast", + "centralus": "westus", + "eastasia": "japaneast", + "eastus": "centralus", + "eastus2": "centralus", + "japaneast": "eastasia", + "northeurope": "westeurope", + "southeastasia": "eastasia", + "uksouth": "westeurope", + "westeurope": "northeurope" + }, + "replicaLocation": "[tryGet(variables('replicaRegionPairs'), parameters('location'))]", + "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", + "jumpboxVmName": "[take(format('vm-{0}', variables('solutionSuffix')), 15)]", + "dataCollectionRulesResourceName": "[format('dcr-{0}', variables('solutionSuffix'))]", + "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", + "dcrLogAnalyticsDestinationName": "[format('la-{0}-destination', variables('logAnalyticsWorkspaceResourceName'))]", + "privateDnsZones": [ + "privatelink.cognitiveservices.azure.com", + "privatelink.openai.azure.com", + "privatelink.services.ai.azure.com", + "privatelink.contentunderstanding.ai.azure.com", + "[format('privatelink.blob.{0}', environment().suffixes.storage)]", + "[format('privatelink.queue.{0}', environment().suffixes.storage)]", + "privatelink.mongo.cosmos.azure.com", + "privatelink.azconfig.io", + "privatelink.azurecr.io" + ], + "dnsZoneIndex": { + "cognitiveServices": 0, + "openAI": 1, + "aiServices": 2, + "contentUnderstanding": 3, + "storageBlob": 4, + "storageQueue": 5, + "cosmosDB": 6, + "appConfig": 7, + "containerRegistry": 8 + } + }, "resources": { - "nsgs": { - "copy": { - "name": "nsgs", - "count": "[length(parameters('subnets'))]", - "mode": "serial", - "batchSize": 1 - }, - "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('46d3xbcp.ptn.sa-contentprocessing.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroupTags": { + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", + "properties": { + "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" + } + }, + "virtualNetwork": { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.network-security-group.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", + "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "addressPrefixes": { + "value": [ + "10.0.0.0/8" + ] }, "location": { "value": "[parameters('location')]" }, - "securityRules": { - "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" - }, "tags": { "value": "[parameters('tags')]" }, + "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "resourceSuffix": { + "value": "[variables('solutionSuffix')]" + }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" } @@ -812,1596 +606,720 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7311263652424030280" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." + "version": "0.42.1.51946", + "templateHash": "10323079586505814920" + } }, "definitions": { - "securityRuleType": { + "subnetOutputType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the security rule." + "description": "The name of the subnet." } }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the subnet." + } + }, + "nsgName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The name of the associated NSG, if any." + } + }, + "nsgResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. The properties of the security rule." + "description": "The resource ID of the associated NSG, if any." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a security rule." + "description": "Subnet output type" } }, - "diagnosticSettingLogsOnlyType": { + "subnetType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Required. The name of the subnet." } }, - "logCategoriesAndGroups": { + "addressPrefixes": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "type": "string" }, - "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. Address prefixes for the subnet." } }, - "logAnalyticsDestinationType": { + "delegation": { "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Optional. Delegation for the subnet." } }, - "workspaceResourceId": { + "privateEndpointNetworkPolicies": { "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Private endpoint network policies." } }, - "storageAccountResourceId": { + "privateLinkServiceNetworkPolicies": { "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Private link service network policies." } }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", + "networkSecurityGroup": { + "$ref": "#/definitions/networkSecurityGroupType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. NSG configuration for the subnet." } }, - "eventHubName": { + "routeTableResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Route table resource ID." } }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. Service endpoint policies." } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. Service endpoints to enable." } }, - "notes": { - "type": "string", + "defaultOutboundAccess": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. Disable default outbound connectivity." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "Subnet configuration type" } }, - "roleAssignmentType": { + "networkSecurityGroupType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Required. The name of the NSG." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "securityRules": { + "type": "array", + "items": { + "type": "object" + }, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Required. Security rules for the NSG." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "NSG configuration type" } } }, "parameters": { - "name": { + "solutionName": { "type": "string", "metadata": { - "description": "Required. Name of the Network Security Group." + "description": "Solution name suffix used to derive the resource name." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Azure region for the resource." } }, - "securityRules": { + "addressPrefixes": { "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + "description": "Address prefixes for the virtual network." } }, - "diagnosticSettings": { + "subnets": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + "$ref": "#/definitions/subnetType" }, - "nullable": true, + "defaultValue": [ + { + "name": "backend", + "addressPrefixes": [ + "10.0.0.0/27" + ], + "networkSecurityGroup": { + "name": "nsg-backend", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "webserverfarm", + "addressPrefixes": [ + "10.0.4.0/27" + ], + "delegation": "Microsoft.Web/serverfarms", + "privateEndpointNetworkPolicies": "Enabled", + "privateLinkServiceNetworkPolicies": "Enabled", + "networkSecurityGroup": { + "name": "nsg-webserverfarm", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "administration", + "addressPrefixes": [ + "10.0.0.32/27" + ], + "networkSecurityGroup": { + "name": "nsg-administration", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + } + }, + { + "name": "AzureBastionSubnet", + "addressPrefixes": [ + "10.0.0.64/26" + ], + "networkSecurityGroup": { + "name": "nsg-bastion", + "securityRules": [ + { + "name": "AllowGatewayManager", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2702, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "GatewayManager", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowHttpsInBound", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2703, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowSshRdpOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 100, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AllowAzureCloudOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 110, + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "AzureCloud" + } + } + ] + } + } + ], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Subnet configurations." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Tags to apply to the resources." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "logAnalyticsWorkspaceId": { + "type": "string", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Resource ID of the Log Analytics Workspace for diagnostics." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" - }, - "description": "Optional. Tags of the NSG resource." - }, - "nullable": true - }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "resourceSuffix": { + "type": "string", + "metadata": { + "description": "Suffix for resource naming." + } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "name": "[format('vnet-{0}', parameters('solutionName'))]" }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "nsgs": { + "copy": { + "name": "nsgs", + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "securityRules": { + "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7311263652424030280" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG)." + }, + "definitions": { + "securityRuleType": { + "type": "object", "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "properties": { + "type": "object", + "properties": { + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the security rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 4096, + "metadata": { + "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "metadata": { + "description": "Required. The properties of the security rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a security rule." } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.virtual-network.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "addressPrefixes": { - "value": "[parameters('addressPrefixes')]" - }, - "subnets": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('subnets'))]", - "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" - } - ] - }, - "diagnosticSettings": { - "value": [ - { - "name": "vnetDiagnostics", - "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", - "logCategoriesAndGroups": [ - { - "categoryGroup": "allLogs", - "enabled": true - } - ], - "metricCategories": [ - { - "category": "AllMetrics", - "enabled": true - } - ] - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "14370126050175308430" - }, - "name": "Virtual Networks", - "description": "This module deploys a Virtual Network (vNet)." - }, - "definitions": { - "peeringType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." - } - }, - "useRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - }, - "remotePeeringEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Deploy the outbound and the inbound peering." - } - }, - "remotePeeringName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." - } - }, - "remotePeeringAllowForwardedTraffic": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "remotePeeringAllowGatewayTransit": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "remotePeeringAllowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "remotePeeringDoNotVerifyRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." - } - }, - "remotePeeringUseRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." - } - }, - "ipamPoolPrefixAllocations": { - "type": "array", - "prefixItems": [ - { + }, + "diagnosticSettingLogsOnlyType": { "type": "object", "properties": { - "pool": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the IPAM pool." + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, "metadata": { - "description": "Required. The Resource ID of the IPAM pool." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "numberOfIpAddresses": { + "workspaceResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Number of IP addresses allocated from the pool." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } - } - } - } - ], - "items": false, - "nullable": true, - "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, - "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Virtual Network (vNet)." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." - } - }, - "ipamPoolNumberOfIpAddresses": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." - } - }, - "virtualNetworkBgpCommunity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The BGP community associated with the virtual network." - } - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An Array of subnets to deploy to the Virtual Network." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. DNS Servers associated to the Virtual Network." - } - }, - "ddosProtectionPlanResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." - } - }, - "peerings": { - "type": "array", - "items": { - "$ref": "#/definitions/peeringType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Virtual Network Peering configurations." - } - }, - "vnetEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." - } - }, - "vnetEncryptionEnforcement": { - "type": "string", - "defaultValue": "AllowUnencrypted", - "allowedValues": [ - "AllowUnencrypted", - "DropUnencrypted" - ], - "metadata": { - "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." - } - }, - "flowTimeoutInMinutes": { - "type": "int", - "defaultValue": 0, - "maxValue": 30, - "metadata": { - "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableVmProtection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." - } - }, - "enablePrivateEndpointVNetPolicies": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Basic", - "Disabled" - ], - "metadata": { - "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", - "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", - "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", - "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", - "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", - "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", - "enableVmProtection": "[parameters('enableVmProtection')]", - "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" - } - }, - "virtualNetwork_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_diagnosticSettings": { - "copy": { - "name": "virtualNetwork_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_roleAssignments": { - "copy": { - "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_subnets": { - "copy": { - "name": "virtualNetwork_subnets", - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualNetworkName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" - }, - "addressPrefix": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" - }, - "addressPrefixes": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" - }, - "ipamPoolPrefixAllocations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" - }, - "applicationGatewayIPConfigurations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" - }, - "delegation": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" - }, - "natGatewayResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" - }, - "networkSecurityGroupResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" - }, - "privateEndpointNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" - }, - "privateLinkServiceNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "routeTableResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" - }, - "serviceEndpointPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" - }, - "serviceEndpoints": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" - }, - "defaultOutboundAccess": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" - }, - "sharingScope": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "17113728662177315319" }, - "name": "Virtual Network Subnets", - "description": "This module deploys a Virtual Network Subnet." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -2473,7 +1391,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } @@ -2482,151 +1400,75 @@ "name": { "type": "string", "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "virtualNetworkName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + "description": "Required. Name of the Network Security Group." } }, - "addressPrefix": { + "location": { "type": "string", - "nullable": true, + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + "description": "Optional. Location for all resources." } }, - "ipamPoolPrefixAllocations": { + "securityRules": { "type": "array", "items": { - "type": "object" + "$ref": "#/definitions/securityRuleType" }, "nullable": true, "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." } }, - "routeTableResourceId": { - "type": "string", - "nullable": true, + "flushConnection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." } }, - "serviceEndpoints": { + "diagnosticSettings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" }, - "defaultValue": [], - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "delegation": { - "type": "string", "nullable": true, "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "metadata": { - "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. The diagnostic settings of the service." } }, - "privateLinkServiceNetworkPolicies": { - "type": "string", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled" - ], "metadata": { - "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + "description": "Optional. The lock settings of the service." } }, - "addressPrefixes": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + "description": "Optional. Array of role assignments to create." } }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, + "tags": { + "type": "object", "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" + }, + "description": "Optional. Tags of the NSG resource." + }, + "nullable": true }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, @@ -2652,7 +1494,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2668,50 +1510,97 @@ } } }, - "virtualNetwork": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[parameters('virtualNetworkName')]" + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(coalesce(parameters('securityRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "properties": { + "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", + "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", + "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", + "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", + "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", + "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", + "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", + "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", + "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", + "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", + "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", + "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", + "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", + "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", + "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } }, - "subnet": { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "networkSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "serviceEndpoints", - "count": "[length(parameters('serviceEndpoints'))]", + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", "input": { - "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } ], - "addressPrefix": "[parameters('addressPrefix')]", - "addressPrefixes": "[parameters('addressPrefixes')]", - "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", - "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", - "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", - "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", - "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", - "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", - "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", - "sharingScope": "[parameters('sharingScope')]" - } - }, - "subnet_roleAssignments": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { "copy": { - "name": "subnet_roleAssignments", + "name": "networkSecurityGroup_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -2722,7 +1611,7 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "subnet" + "networkSecurityGroup" ] } }, @@ -2730,1928 +1619,2469 @@ "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the virtual network peering was deployed into." + "description": "The resource group the network security group was deployed into." }, "value": "[resourceGroup().name]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource ID of the network security group." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" }, - "addressPrefix": { + "name": { "type": "string", "metadata": { - "description": "The address prefix for the subnet." - }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "List of address prefixes for the subnet." + "description": "The name of the network security group." }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + "value": "[parameters('name')]" }, - "ipamPoolPrefixAllocations": { - "type": "array", + "location": { + "type": "string", "metadata": { - "description": "The IPAM pool prefix allocations for the subnet." + "description": "The location the resource was deployed into." }, - "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" } } } - }, - "dependsOn": [ - "virtualNetwork" - ] + } }, - "virtualNetwork_peering_local": { - "copy": { - "name": "virtualNetwork_peering_local", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" - }, + "virtualNetwork": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "localVnetName": { - "value": "[parameters('name')]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" - }, "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + "value": "[variables('name')]" }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + "location": { + "value": "[parameters('location')]" }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + "addressPrefixes": { + "value": "[parameters('addressPrefixes')]" }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + "subnets": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('subnets'))]", + "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" + } + ] }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + "diagnosticSettings": { + "value": [ + { + "name": "vnetDiagnostics", + "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs", + "enabled": true + } + ], + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "17951311301958631828" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." - } + "version": "0.41.2.15936", + "templateHash": "11272001757446231867" }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet)." }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork-peering.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "definitions": { + "peeringType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." } } - } - }, - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", - "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" - ] - }, - "virtualNetwork_peering_remote": { - "copy": { - "name": "virtualNetwork_peering_remote", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" - }, - "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", - "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "localVnetName": { - "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" - }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" - }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" - }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" - }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" - }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "17951311301958631828" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + "__bicep_export!": true } }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork-peering.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "subnetType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "prefixItems": [ + { + "type": "object", + "properties": { + "pool": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + } + }, + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + }, + "numberOfIpAddresses": { + "type": "string", + "metadata": { + "description": "Required. Number of IP addresses allocated from the pool." + } + } + } } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." } } + }, + "metadata": { + "__bicep_export!": true } }, - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "diagnosticSettingFullType": { + "type": "object", "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "description": "The name of the virtual network peering." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } }, - "value": "[parameters('name')]" + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } }, - "resourceId": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." + } + }, + "ipamPoolNumberOfIpAddresses": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + }, + "enablePrivateEndpointVNetPolicies": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Basic", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." + } } - } - } - }, - "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network." - }, - "value": "[parameters('name')]" - }, - "subnetNames": { - "type": "array", - "metadata": { - "description": "The names of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" - } - }, - "subnetResourceIds": { - "type": "array", - "metadata": { - "description": "The resource IDs of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "nsgs" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.name.value]" - }, - "resourceId": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetOutputType" - }, - "copy": { - "count": "[length(parameters('subnets'))]", - "input": { - "name": "[parameters('subnets')[copyIndex()].name]", - "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", - "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", - "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" - } - } - }, - "containersSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'containers'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'containers')], '')]" - }, - "backendSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" - }, - "bastionSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" - }, - "adminSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'admin'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'admin')], '')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "bastionHost": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('bastionHostName')]" - }, - "skuName": { - "value": "Standard" - }, - "location": { - "value": "[parameters('location')]" - }, - "virtualNetworkResourceId": { - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "publicIPAddressObject": { - "value": { - "name": "[format('pip-{0}', variables('bastionHostName'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7741601918225805390" - }, - "name": "Bastion Hosts", - "description": "This module deploys a Bastion Host." - }, - "definitions": { - "publicIPAddressObjectType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for the Public IP resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create for the Public IP resource." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable usage telemetry for the Public IP module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Idle timeout in minutes for the Public IP resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to apply to the Public IP resource." - }, - "nullable": true - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the Public IP resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure Bastion resource." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Shared services Virtual Network resource Id." - } - }, - "bastionSubnetPublicIpResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "publicIPAddressObject": { - "$ref": "#/definitions/publicIPAddressObjectType", - "defaultValue": { - "name": "[format('{0}-pip', parameters('name'))]" - }, - "metadata": { - "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Basic", - "allowedValues": [ - "Basic", - "Developer", - "Premium", - "Standard" - ], - "metadata": { - "description": "Optional. The SKU of this Bastion Host." - } - }, - "disableCopyPaste": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." - } - }, - "enableFileCopy": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." - } - }, - "enableIpConnect": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." - } - }, - "enableKerberos": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." - } - }, - "enableShareableLink": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." - } - }, - "enableSessionRecording": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." - } - }, - "enablePrivateOnlyBastion": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." - } - }, - "scaleUnits": { - "type": "int", - "defaultValue": 2, - "metadata": { - "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. The list of Availability zones to use for the zone-redundant resources." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "azureBastion": { - "type": "Microsoft.Network/bastionHosts", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[coalesce(parameters('tags'), createObject())]", - "sku": { - "name": "[parameters('skuName')]" - }, - "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", - "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", - "dependsOn": [ - "publicIPAddress" - ] - }, - "azureBastion_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_diagnosticSettings": { - "copy": { - "name": "azureBastion_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_roleAssignments": { - "copy": { - "name": "azureBastion_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "publicIPAddress": { - "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('publicIPAddressObject').name]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" - }, - "ipTags": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" - }, - "publicIPAddressVersion": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" - }, - "publicIPAllocationMethod": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" - }, - "publicIpPrefixResourceId": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" - }, - "skuName": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" - }, - "skuTier": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" - }, - "availabilityZones": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "16564959277054027786" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." - }, - "definitions": { - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]", + "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "ipamPoolPrefixAllocations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13992200806189615656" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + } + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "metadata": { + "description": "The IPAM pool prefix allocations for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + } + } } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } } - } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] } }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "nsgs" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.name.value]" + }, + "resourceId": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetOutputType" + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex()].name]", + "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", + "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", + "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" + } + } + }, + "backendSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" + }, + "webserverfarmSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" + }, + "administrationSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" + }, + "bastionSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "bastionHost": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('bastionHostName')]" + }, + "skuName": { + "value": "Standard" + }, + "location": { + "value": "[parameters('location')]" + }, + "virtualNetworkResourceId": { + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": { + "name": "[format('pip-{0}', variables('bastionHostName'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7741601918225805390" + }, + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host." + }, + "definitions": { + "publicIPAddressObjectType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." } }, - "logAnalyticsDestinationType": { + "publicIPAllocationMethod": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "Dynamic", + "Static" ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Optional. The public IP address allocation method." } }, - "workspaceResourceId": { - "type": "string", + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." } }, - "storageAccountResourceId": { + "publicIPAddressVersion": { "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. IP address version." } }, - "eventHubAuthorizationRuleResourceId": { + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. Name of a public IP address SKU." } }, - "eventHubName": { + "skuTier": { "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Tier of a public IP address SKU." } }, - "marketplacePartnerResourceId": { + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. Location for the Public IP resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create for the Public IP resource." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the Public IP module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Idle timeout in minutes for the Public IP resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to apply to the Public IP resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the Public IP resource." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "__bicep_export!": true, + "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." } }, - "lockType": { + "ddosSettingsType": { "type": "object", "properties": { - "name": { - "type": "string", + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The DDoS protection plan associated with the public IP address." } }, - "kind": { + "protectionMode": { "type": "string", "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" + "Enabled" ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Required. The DDoS protection policy customizations." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" } } }, - "roleAssignmentType": { + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Optional. The name of the diagnostic setting." } }, - "roleDefinitionIdOrName": { - "type": "string", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "principalId": { - "type": "string", + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." } }, - "principalType": { + "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "AzureDiagnostics", + "Dedicated" ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "description": { + "workspaceResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "condition": { + "storageAccountResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "conditionVersion": { + "eventHubAuthorizationRuleResourceId": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "delegatedManagedIdentityResourceId": { + "eventHubName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", "__bicep_imported_from!": { "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, "metadata": { - "description": "Optional. IP address version." + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Bastion resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "virtualNetworkResourceId": { + "type": "string", "metadata": { - "description": "Optional. The DNS settings of the public IP address." + "description": "Required. Shared services Virtual Network resource Id." } }, - "ipTags": { + "bastionSubnetPublicIpResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "publicIPAddressObject": { + "$ref": "#/definitions/publicIPAddressObjectType", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/ipTagType" + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" }, "nullable": true, "metadata": { - "description": "Optional. The list of tags associated with the public IP address." + "description": "Optional. The diagnostic settings of the service." } }, "lock": { @@ -4663,93 +4093,113 @@ }, "skuName": { "type": "string", - "defaultValue": "Standard", + "defaultValue": "Basic", "allowedValues": [ "Basic", + "Developer", + "Premium", "Standard" ], "metadata": { - "description": "Optional. Name of a public IP address SKU." + "description": "Optional. The SKU of this Bastion Host." } }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Tier of a public IP address SKU." + "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." } }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, + "enableFileCopy": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." } }, - "deleteOption": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Delete", - "Detach" - ], + "enableIpConnect": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The delete option for the public IP address." + "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "enableKerberos": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." } }, - "enableTelemetry": { + "enableSessionRecording": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." + } + }, + "enablePrivateOnlyBastion": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." } }, - "idleTimeoutInMinutes": { + "scaleUnits": { "type": "int", - "defaultValue": 4, + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. The idle timeout of the public IP address." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" }, "description": "Optional. Tags of the resource." }, "nullable": true }, - "diagnosticSettings": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "availabilityZones": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "type": "int" }, - "nullable": true, + "defaultValue": [], + "allowedValues": [ + 1, + 2, + 3 + ], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. The list of Availability zones to use for the zone-redundant resources." } } }, @@ -4761,17 +4211,13 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "enableReferencedModulesTelemetry": false, "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { @@ -4779,7 +4225,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -4795,84 +4241,46 @@ } } }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", "apiVersion": "2025-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "tags": "[coalesce(parameters('tags'), createObject())]", "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" + "name": "[parameters('skuName')]" }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" - } + "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", + "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] }, - "publicIpAddress_lock": { + "azureBastion_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" + "azureBastion" ] }, - "publicIpAddress_diagnosticSettings": { + "azureBastion_diagnosticSettings": { "copy": { - "name": "publicIpAddress_diagnosticSettings", + "name": "azureBastion_diagnosticSettings", "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, { "name": "logs", "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", @@ -4891,9016 +4299,839 @@ "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "publicIpAddress" + "azureBastion" ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + "dependsOn": [ + "azureBastion" + ] }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" - } - } - } - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the Azure Bastion was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name the Azure Bastion." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID the Azure Bastion." - }, - "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('azureBastion', '2025-01-01', 'full').location]" - }, - "ipConfAzureBastionSubnet": { - "type": "object", - "metadata": { - "description": "The Public IPconfiguration object for the AzureBastionSubnet." - }, - "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "jumpboxVM": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('jumpboxVmName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "computerName": { - "value": "[take(variables('jumpboxVmName'), 15)]" - }, - "osType": { - "value": "Windows" - }, - "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", - "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", - "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "patchMode": { - "value": "AutomaticByPlatform" - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "value": true - }, - "maintenanceConfigurationResourceId": { - "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" - }, - "enableAutomaticUpdates": { - "value": true - }, - "encryptionAtHost": { - "value": false - }, - "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", - "imageReference": { - "value": { - "publisher": "microsoft-dsvm", - "offer": "dsvm-win-2022", - "sku": "winserver-2022", - "version": "latest" - } - }, - "osDisk": { - "value": { - "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", - "caching": "ReadWrite", - "createOption": "FromImage", - "deleteOption": "Delete", - "diskSizeGB": 128, - "managedDisk": { - "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" - } - } - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-{0}', variables('jumpboxVmName'))]", - "tags": "[parameters('tags')]", - "deleteOption": "Delete", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", - "ipConfigurations": [ - { - "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", - "subnetResourceId": "[reference('virtualNetwork').outputs.adminSubnetResourceId.value]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" - } - ] - } - ] - }, - "extensionAadJoinConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]", - "typeHandlerVersion": "1.0", - "settings": { - "mdmId": "" - } - } - }, - "extensionAntiMalwareConfig": { - "value": { - "enabled": true, - "settings": { - "AntimalwareEnabled": "true", - "Exclusions": {}, - "RealtimeProtectionEnabled": "true", - "ScheduledScanSettings": { - "day": "7", - "isEnabled": "true", - "scanType": "Quick", - "time": "120" - } - }, - "tags": "[parameters('tags')]" - } - }, - "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", - "extensionNetworkWatcherAgentConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17174537341033050778" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." - }, - "definitions": { - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "diffDiskSettings": { - "type": "object", - "properties": { - "placement": { - "type": "string", - "allowedValues": [ - "CacheDisk", - "NvmeDisk", - "ResourceDisk" - ], - "metadata": { - "description": "Required. Specifies the ephemeral disk placement for the operating system disk." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing an OS disk." - } - }, - "dataDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." - } - }, - "diskIOPSReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." - } - }, - "diskMBpsReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" - }, - "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing a data disk." - } - }, - "publicKeyType": { - "type": "object", - "properties": { - "keyData": { - "type": "string", - "metadata": { - "description": "Required. Specifies the SSH public key data used to authenticate through ssh." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." - } - } - } - }, - "nicConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the NIC configuration." - } - }, - "nicSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The suffix to append to the NIC name." - } - }, - "enableIPForwarding": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify what happens to the network interface when the VM is deleted." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "metadata": { - "description": "Required. The IP configurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags of the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the NIC configuration." - } - }, - "imageReferenceType": { - "type": "object", - "properties": { - "communityGalleryImageId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." - } - }, - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the image reference." - } - }, - "offer": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The image publisher." - } - }, - "sku": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The SKU of the image." - } - }, - "version": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." - } - }, - "sharedGalleryImageId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the image reference." - } - }, - "planType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the plan." - } - }, - "product": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the product of the image from the marketplace." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher ID." - } - }, - "promotionCode": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The promotion code." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Specifies information about the marketplace image used to create the virtual machine." - } - }, - "autoShutDownConfigType": { - "type": "object", - "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the auto shutdown configuration." - } - }, - "timeZone": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." - } - }, - "dailyRecurrenceTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time of day the schedule will occur." - } - }, - "notificationSettings": { - "type": "object", - "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the notification settings." - } - }, - "emailRecipient": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." - } - }, - "notificationLocale": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." - } - }, - "webhookUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The webhook URL to which the notification will be sent." - } - }, - "timeInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The time in minutes before shutdown to send notifications." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the schedule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the configuration profile." - } - }, - "vaultSecretGroupType": { - "type": "object", - "properties": { - "sourceVault": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." - } - }, - "vaultCertificates": { - "type": "array", - "items": { - "type": "object", - "properties": { - "certificateStore": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." - } - }, - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of key vault references in SourceVault which contain certificates." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the set of certificates that should be installed onto the virtual machine." - } - }, - "vmGalleryApplicationType": { - "type": "object", - "properties": { - "packageReferenceId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." - } - }, - "configurationReference": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." - } - }, - "order": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the order in which the packages have to be installed." - } - }, - "tags": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies a passthrough value for more generic context." - } - }, - "treatFailureAsDeploymentFailure": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the gallery application that should be made available to the VM/VMSS." - } - }, - "additionalUnattendContentType": { - "type": "object", - "properties": { - "settingName": { - "type": "string", - "allowedValues": [ - "AutoLogon", - "FirstLogonCommands" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the name of the setting to which the content applies." - } - }, - "content": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." - } - }, - "winRMListenerType": { - "type": "object", - "properties": { - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "Http", - "Https" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the protocol of WinRM listener." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing a Windows Remote Management listener." - } - }, - "nicConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NIC configuration." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "Required. List of IP configurations of the NIC configuration." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the network interface configuration output." - } - }, - "extensionCustomScriptConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." - } - }, - "typeHandlerVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." - } - }, - "fileUris": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "protectedSettings": { - "type": "secureObject", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." - } - }, - "storageAccountName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." - } - }, - "storageAccountKey": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The access key of the storage account." - } - }, - "managedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." - } - }, - "fileUris": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. URLs for files to be downloaded." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "supressFailures": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a 'CustomScriptExtension' extension." - } - }, - "_1.applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } + "publicIPAddress": { + "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_2.ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_2.dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_2.ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_3.diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_3.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_3.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_4.publicIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Public IP Address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout in minutes." - } - }, - "lock": { - "$ref": "#/definitions/_3.lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the public IP address." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "ddosSettings": { - "$ref": "#/definitions/_2.ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "dnsSettings": { - "$ref": "#/definitions/_2.dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address version." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIpNameSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name suffix of the public IP address resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU tier of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], - "nullable": true, - "metadata": { - "description": "Optional. The zones of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "description": "The type for the public IP address configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer backend address pools." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application security groups." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application gateway backend address pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The gateway load balancer settings." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer inbound NAT rules." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address version." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The virtual network taps." - } - }, - "pipConfiguration": { - "$ref": "#/definitions/_4.publicIPConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The public IP address configuration." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "description": "The type for the IP configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "description": "The type for the network interface IP configuration output.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" - }, - "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." - }, - "nullable": true - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" - }, - "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." - }, - "nullable": true - }, - "plan": { - "$ref": "#/definitions/planType", - "nullable": true, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "type": "array", - "items": { - "$ref": "#/definitions/dataDiskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "hibernationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables hibernation capability on the VM." - } - }, - "adminUsername": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." - } - }, - "userData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "items": { - "$ref": "#/definitions/vaultSecretGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "evictionPolicy": { - "type": "string", - "defaultValue": "Deallocate", - "allowedValues": [ - "Deallocate", - "Delete" - ], - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "publicKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/publicKeyType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "galleryApplications": { - "type": "array", - "items": { - "$ref": "#/definitions/vmGalleryApplicationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." - } - }, - "availabilityZone": { - "type": "int", - "allowedValues": [ - -1, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." - } - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationType" - }, - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Recovery service vault name to add VMs to backup." - } - }, - "backupVaultResourceGroup": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." - } - }, - "backupPolicyName": { - "type": "string", - "defaultValue": "DefaultPolicy", - "metadata": { - "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." - } - }, - "autoShutdownConfig": { - "$ref": "#/definitions/autoShutDownConfigType", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for auto-shutdown." - } - }, - "maintenanceConfigurationResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The resource Id of a maintenance configuration for this VM." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAntiMalwareConfig": { - "type": "object", - "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", - "metadata": { - "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionMonitoringAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "dataCollectionRuleAssociations": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionDependencyAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNetworkWatcherAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "$ref": "#/definitions/extensionCustomScriptConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionHostPoolRegistration": { - "type": "secureObject", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "extensionGuestConfigurationExtension": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "guestConfiguration": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." - } - }, - "extensionGuestConfigurationExtensionProtectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "disablePasswordAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether password authentication should be disabled." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "enableHotpatching": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "items": { - "$ref": "#/definitions/additionalUnattendContentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRMListeners": { - "type": "array", - "items": { - "$ref": "#/definitions/winRMListenerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - }, - "capacityReservationGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." - } - }, - "networkAccessPolicy": { - "type": "string", - "defaultValue": "DenyAll", - "allowedValues": [ - "AllowAll", - "AllowPrivate", - "DenyAll" - ], - "metadata": { - "description": "Optional. Policy for accessing the disk via network." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Policy for controlling export on the disk." - } - } - }, - "variables": { - "copy": [ - { - "name": "publicKeysFormatted", - "count": "[length(parameters('publicKeys'))]", - "input": { - "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", - "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" - } - }, - { - "name": "additionalUnattendContentFormatted", - "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", - "input": { - "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", - "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", - "componentName": "Microsoft-Windows-Shell-Setup", - "passName": "OobeSystem" - } - }, - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "linuxConfiguration": { - "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", - "ssh": { - "publicKeys": "[variables('publicKeysFormatted')]" - }, - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" - }, - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", - "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", - "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", - "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", - "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", - "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", - "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", - "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", - "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", - "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", - "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", - "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", - "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" - }, - "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", - "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "managedDataDisks": { - "copy": { - "name": "managedDataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" - }, - "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", - "type": "Microsoft.Compute/disks", - "apiVersion": "2025-01-02", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", - "location": "[parameters('location')]", - "sku": { - "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" - }, - "properties": { - "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", - "creationData": { - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" - }, - "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", - "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "networkAccessPolicy": "[parameters('networkAccessPolicy')]" - }, - "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", - "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", - "plan": "[parameters('plan')]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", - "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", - "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", - "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", - "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", - "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", - "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", - "osType": "[parameters('osType')]", - "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", - "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", - "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", - "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", - "managedDisk": { - "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", - "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", - "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", - "hibernationEnabled": "[parameters('hibernationEnabled')]" - }, - "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" - } - } - ] - }, - "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", - "licenseType": "[parameters('licenseType')]", - "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" - }, - "dependsOn": [ - "managedDataDisks", - "vm_nic" - ] - }, - "vm_configurationAssignment": { - "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", - "type": "Microsoft.Maintenance/configurationAssignments", - "apiVersion": "2023-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[format('{0}assignment', parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", - "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_autoShutdownConfiguration": { - "condition": "[not(empty(parameters('autoShutdownConfig')))]", - "type": "Microsoft.DevTestLab/schedules", - "apiVersion": "2018-09-15", - "name": "[format('shutdown-computevm-{0}', parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", - "properties": { - "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", - "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "taskType": "ComputeVmShutdownTask", - "dailyRecurrence": { - "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" - }, - "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", - "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_dataCollectionRuleAssociations": { - "copy": { - "name": "vm_dataCollectionRuleAssociations", - "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" - }, - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Insights/dataCollectionRuleAssociations", - "apiVersion": "2024-03-11", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", - "properties": { - "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "cseIdentity": { - "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", - "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" - }, - "AzureWindowsBaseline": { - "condition": "[not(empty(parameters('guestConfiguration')))]", - "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", - "apiVersion": "2024-04-05", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", - "location": "[parameters('location')]", - "properties": { - "guestConfiguration": "[parameters('guestConfiguration')]" - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - }, - "vm_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_roleAssignments": { - "copy": { - "name": "vm_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" - }, - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableIPForwarding": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" - }, - "enableAcceleratedNetworking": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" - }, - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" - }, - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "lock": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "5982155361487304817" - } - }, - "definitions": { - "publicIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Public IP Address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout in minutes." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the public IP address." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address version." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIpNameSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name suffix of the public IP address resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU tier of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], - "nullable": true, - "metadata": { - "description": "Optional. The zones of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the public IP address configuration." - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer backend address pools." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application security groups." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application gateway backend address pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The gateway load balancer settings." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer inbound NAT rules." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address version." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The virtual network taps." - } - }, - "pipConfiguration": { - "$ref": "#/definitions/publicIPConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The public IP address configuration." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the IP configuration." - } - }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - } - }, - "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [] - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "networkInterface_publicIPAddresses": { - "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" - }, - "diagnosticSettings": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" - }, - "ddosSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" - }, - "publicIPAddressVersion": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" - }, - "publicIPAllocationMethod": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" - }, - "publicIpPrefixResourceId": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" - }, - "roleAssignments": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" - }, - "skuName": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" - }, - "skuTier": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "availabilityZones": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" - }, - "enableTelemetry": { - "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" - }, - "ipTags": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5349747633189946992" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" - }, - "description": "Optional. The public IP address allocation method." - }, - "defaultValue": "Static" - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" - }, - "description": "Optional. IP address version." - }, - "defaultValue": "IPv4" - }, - "dnsSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" - }, - "description": "Optional. The DNS settings of the public IP address." - }, - "nullable": true - }, - "ipTags": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" - }, - "description": "Optional. The list of tags associated with the public IP address." - }, - "nullable": true - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" - }, - "description": "Optional. Name of a public IP address SKU." - }, - "defaultValue": "Standard" - }, - "skuTier": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" - }, - "description": "Optional. Tier of a public IP address SKU." - }, - "defaultValue": "Regional" - }, - "ddosSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" - }, - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - }, - "nullable": true - }, - "deleteOption": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" - }, - "description": "Optional. The delete option for the public IP address." - }, - "nullable": true - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" - } - }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "272838238520810437" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface." - }, - "definitions": { - "networkInterfaceIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of load balancer backend address pools." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of references of LoadBalancerInboundNatRules." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the IP configuration is included." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Application Gateway Backend Address Pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The reference to gateway load balancer frontend IP." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Virtual Network Taps." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The resource ID of the deployed resource." - } - }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backend address pool." - } - }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the application security group." - } - }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the application gateway backend address pool." - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the sub resource." - } - }, - "inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the inbound NAT rule." - } - }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network tap." - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network interface IP configuration output." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationType" - }, - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "publicIp": { - "copy": { - "name": "publicIp", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", - "existing": true, - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2024-05-01", - "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", - "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", - "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", - "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", - "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", - "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", - "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", - "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed resource." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkInterface', '2024-05-01', 'full').location]" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "The list of IP configurations of the network interface." - }, - "copy": { - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", - "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", - "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" - } - } - } - } - } - }, - "dependsOn": [ - "networkInterface_publicIPAddresses" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the network interface." - }, - "value": "[reference('networkInterface').outputs.name.value]" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "The list of IP configurations of the network interface." - }, - "value": "[reference('networkInterface').outputs.ipConfigurations.value]" - } - } - } - } - }, - "vm_domainJoinExtension": { - "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_domainJoinExtension" - ] - }, - "vm_microsoftAntiMalwareExtension": { - "condition": "[parameters('extensionAntiMalwareConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": { - "value": "IaaSAntimalware" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_azureMonitorAgentExtension": { - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitor" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_microsoftAntiMalwareExtension" - ] - }, - "vm_dependencyAgentExtension": { - "condition": "[parameters('extensionDependencyAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitoring.DependencyAgent" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" - }, - "settings": { - "value": { - "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "vm_networkWatcherAgentExtension": { - "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.NetworkWatcher" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_dependencyAgentExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_networkWatcherAgentExtension" - ] - }, - "vm_customScriptExtension": { - "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" - }, - "provisionAfterExtensions": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettingsFromKeyVault": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" - }, - "settings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" - }, - "protectedSettings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "cseIdentity", - "vm" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_customScriptExtension" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - }, - "vm_hostPoolRegistrationExtension": { - "condition": "[parameters('extensionHostPoolRegistration').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.PowerShell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": { - "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", - "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", - "properties": { - "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", - "aadJoin": true - } - } - }, - "protectedSettings": { - "value": { - "properties": { - "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" - } - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" + }, + "ipTags": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" + } }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_nvidiaGpuDriverWindowsExtension" - ] - }, - "vm_azureGuestConfigurationExtension": { - "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.GuestConfiguration" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" - }, - "protectedSettings": { - "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "16564959277054027786" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "deleteOption": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Delete", + "Detach" + ], + "metadata": { + "description": "Optional. The delete option for the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } } - }, - "forceUpdateTag": { + } + }, + "outputs": { + "resourceGroupName": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + "description": "The resource group the Azure Bastion was deployed into." }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" + "value": "[resourceGroup().name]" }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the extension." + "description": "The name the Azure Bastion." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the extension." + "description": "The resource ID the Azure Bastion." }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The name of the Resource Group the extension was created in." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('azureBastion', '2025-01-01', 'full').location]" }, - "location": { - "type": "string", + "ipConfAzureBastionSubnet": { + "type": "object", "metadata": { - "description": "The location the resource was deployed into." + "description": "The Public IPconfiguration object for the AzureBastionSubnet." }, - "value": "[reference('extension', '2024-11-01', 'full').location]" + "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" } } } }, "dependsOn": [ - "vm", - "vm_hostPoolRegistrationExtension" + "logAnalyticsWorkspace", + "virtualNetwork" ] }, - "vm_backup": { - "condition": "[not(empty(parameters('backupVaultName')))]", + "jumpboxVM": { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", - "resourceGroup": "[parameters('backupVaultResourceGroup')]", + "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -13908,1551 +5139,2075 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + "value": "[variables('jumpboxVmName')]" }, "location": { "value": "[parameters('location')]" }, - "policyId": { - "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "computerName": { + "value": "[take(variables('jumpboxVmName'), 15)]" + }, + "osType": { + "value": "Windows" + }, + "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", + "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", + "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": true + }, + "maintenanceConfigurationResourceId": { + "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", + "imageReference": { + "value": { + "publisher": "microsoft-dsvm", + "offer": "dsvm-win-2022", + "sku": "winserver-2022", + "version": "latest" + } + }, + "osDisk": { + "value": { + "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" + } + } }, - "protectedItemType": { - "value": "Microsoft.Compute/virtualMachines" + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-{0}', variables('jumpboxVmName'))]", + "tags": "[parameters('tags')]", + "deleteOption": "Delete", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", + "ipConfigurations": [ + { + "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", + "subnetResourceId": "[reference('virtualNetwork').outputs.administrationSubnetResourceId.value]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" + } + ] + } + ] }, - "protectionContainerName": { - "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]", + "typeHandlerVersion": "1.0", + "settings": { + "mdmId": "" + } + } }, - "recoveryVaultName": { - "value": "[parameters('backupVaultName')]" + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": {}, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + }, + "tags": "[parameters('tags')]" + } }, - "sourceResourceId": { - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]" + } } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "17448691641471706096" + "templateHash": "17174537341033050778" }, - "name": "Recovery Service Vaults Protection Container Protected Item", - "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." }, - "parameters": { - "name": { - "type": "string", + "definitions": { + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "diffDiskSettings": { + "type": "object", + "properties": { + "placement": { + "type": "string", + "allowedValues": [ + "CacheDisk", + "NvmeDisk", + "ResourceDisk" + ], + "metadata": { + "description": "Required. Specifies the ephemeral disk placement for the operating system disk." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + }, "metadata": { - "description": "Required. Name of the resource." + "__bicep_export!": true, + "description": "The type describing an OS disk." } }, - "protectionContainerName": { - "type": "string", + "dataDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" + }, + "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." + }, + "nullable": true + } + }, "metadata": { - "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type describing a data disk." } }, - "recoveryVaultName": { - "type": "string", + "publicKeyType": { + "type": "object", + "properties": { + "keyData": { + "type": "string", + "metadata": { + "description": "Required. Specifies the SSH public key data used to authenticate through ssh." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." + } + } + } + }, + "nicConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the NIC configuration." + } + }, + "nicSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The suffix to append to the NIC name." + } + }, + "enableIPForwarding": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify what happens to the network interface when the VM is deleted." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "metadata": { + "description": "Required. The IP configurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for the NIC configuration." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "imageReferenceType": { + "type": "object", + "properties": { + "communityGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." + } + }, + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource Id of the image reference." + } + }, + "offer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The image publisher." + } + }, + "sku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SKU of the image." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." + } + }, + "sharedGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." + } + } + }, "metadata": { - "description": "Optional. Location for all resources." + "__bicep_export!": true, + "description": "The type describing the image reference." } }, - "protectedItemType": { - "type": "string", - "allowedValues": [ - "AzureFileShareProtectedItem", - "AzureVmWorkloadSAPAseDatabase", - "AzureVmWorkloadSAPHanaDatabase", - "AzureVmWorkloadSQLDatabase", - "DPMProtectedItem", - "GenericProtectedItem", - "MabFileFolderProtectedItem", - "Microsoft.ClassicCompute/virtualMachines", - "Microsoft.Compute/virtualMachines", - "Microsoft.Sql/servers/databases" - ], + "planType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the plan." + } + }, + "product": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the product of the image from the marketplace." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher ID." + } + }, + "promotionCode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The promotion code." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Specifies information about the marketplace image used to create the virtual machine." + } + }, + "autoShutDownConfigType": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the auto shutdown configuration." + } + }, + "timeZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." + } + }, + "dailyRecurrenceTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time of day the schedule will occur." + } + }, + "notificationSettings": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the notification settings." + } + }, + "emailRecipient": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." + } + }, + "notificationLocale": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + } + }, + "webhookUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The webhook URL to which the notification will be sent." + } + }, + "timeInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The time in minutes before shutdown to send notifications." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the schedule." + } + } + }, "metadata": { - "description": "Required. The backup item type." + "__bicep_export!": true, + "description": "The type describing the configuration profile." } }, - "policyId": { - "type": "string", + "vaultSecretGroupType": { + "type": "object", + "properties": { + "sourceVault": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." + } + }, + "vaultCertificates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "certificateStore": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + } + }, + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of key vault references in SourceVault which contain certificates." + } + } + }, "metadata": { - "description": "Required. ID of the backup policy with which this item is backed up." + "__bicep_export!": true, + "description": "The type describing the set of certificates that should be installed onto the virtual machine." } }, - "sourceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource to back up." - } - } - }, - "resources": [ - { - "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", - "apiVersion": "2025-02-01", - "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", - "location": "[parameters('location')]", + "vmGalleryApplicationType": { + "type": "object", "properties": { - "protectedItemType": "[parameters('protectedItemType')]", - "policyId": "[parameters('policyId')]", - "sourceResourceId": "[parameters('sourceResourceId')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the protected item was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the protected item." + "packageReferenceId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." + } + }, + "configurationReference": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." + } + }, + "order": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the order in which the packages have to be installed." + } + }, + "tags": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies a passthrough value for more generic context." + } + }, + "treatFailureAsDeploymentFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." + } + } }, - "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" - }, - "name": { - "type": "string", "metadata": { - "description": "The Name of the protected item." - }, - "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2024-07-01', 'full').location]" - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationOutputType" - }, - "metadata": { - "description": "The list of NIC configurations of the virtual machine." - }, - "copy": { - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", - "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" - } - } - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "maintenanceConfiguration", - "virtualNetwork", - "windowsVmDataCollectionRules" - ] - }, - "maintenanceConfiguration": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('mc-{0}', variables('jumpboxVmName'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "extensionProperties": { - "value": { - "InGuestPatchMode": "User" - } - }, - "maintenanceScope": { - "value": "InGuestPatch" - }, - "maintenanceWindow": { - "value": { - "startDateTime": "2024-06-16 00:00", - "duration": "03:55", - "timeZone": "W. Europe Standard Time", - "recurEvery": "1Day" - } - }, - "visibility": { - "value": "Custom" - }, - "installPatches": { - "value": { - "rebootSetting": "IfRequired", - "windowsParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - }, - "linuxParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - } - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14895287194406877557" - }, - "name": "Maintenance Configurations", - "description": "This module deploys a Maintenance Configuration." - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Maintenance Configuration Name." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "extensionProperties": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" - }, - "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." - }, - "defaultValue": {} - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "maintenanceScope": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" - }, - "description": "Optional. Gets or sets maintenanceScope of the configuration." - }, - "defaultValue": "Host" - }, - "maintenanceWindow": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" - }, - "description": "Optional. Definition of a MaintenanceWindow." - }, - "defaultValue": {} - }, - "namespace": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Gets or sets namespace of the resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" - }, - "description": "Optional. Gets or sets tags of the resource." - }, - "nullable": true - }, - "visibility": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" - }, - "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." - }, - "nullable": true - }, - "installPatches": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" - }, - "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." - }, - "defaultValue": {} - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "maintenanceConfiguration": { - "type": "Microsoft.Maintenance/maintenanceConfigurations", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "extensionProperties": "[parameters('extensionProperties')]", - "maintenanceScope": "[parameters('maintenanceScope')]", - "maintenanceWindow": "[parameters('maintenanceWindow')]", - "namespace": "[parameters('namespace')]", - "visibility": "[parameters('visibility')]", - "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" - } - }, - "maintenanceConfiguration_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - }, - "maintenanceConfiguration_roleAssignments": { - "copy": { - "name": "maintenanceConfiguration_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Maintenance Configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Maintenance Configuration." - }, - "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Maintenance Configuration was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the Maintenance Configuration was created in." - }, - "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" - } - } - } - } - }, - "windowsVmDataCollectionRules": { - "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('dataCollectionRulesResourceName')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "location": { - "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" - }, - "dataCollectionRuleProperties": { - "value": { - "kind": "Windows", - "dataSources": { - "performanceCounters": [ - { - "streams": [ - "Microsoft-Perf" - ], - "samplingFrequencyInSeconds": 60, - "counterSpecifiers": [ - "\\Processor Information(_Total)\\% Processor Time", - "\\Processor Information(_Total)\\% Privileged Time", - "\\Processor Information(_Total)\\% User Time", - "\\Processor Information(_Total)\\Processor Frequency", - "\\System\\Processes", - "\\Process(_Total)\\Thread Count", - "\\Process(_Total)\\Handle Count", - "\\System\\System Up Time", - "\\System\\Context Switches/sec", - "\\System\\Processor Queue Length", - "\\Memory\\% Committed Bytes In Use", - "\\Memory\\Available Bytes", - "\\Memory\\Committed Bytes", - "\\Memory\\Cache Bytes", - "\\Memory\\Pool Paged Bytes", - "\\Memory\\Pool Nonpaged Bytes", - "\\Memory\\Pages/sec", - "\\Memory\\Page Faults/sec", - "\\Process(_Total)\\Working Set", - "\\Process(_Total)\\Working Set - Private", - "\\LogicalDisk(_Total)\\% Disk Time", - "\\LogicalDisk(_Total)\\% Disk Read Time", - "\\LogicalDisk(_Total)\\% Disk Write Time", - "\\LogicalDisk(_Total)\\% Idle Time", - "\\LogicalDisk(_Total)\\Disk Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Transfers/sec", - "\\LogicalDisk(_Total)\\Disk Reads/sec", - "\\LogicalDisk(_Total)\\Disk Writes/sec", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", - "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", - "\\LogicalDisk(_Total)\\% Free Space", - "\\LogicalDisk(_Total)\\Free Megabytes", - "\\Network Interface(*)\\Bytes Total/sec", - "\\Network Interface(*)\\Bytes Sent/sec", - "\\Network Interface(*)\\Bytes Received/sec", - "\\Network Interface(*)\\Packets/sec", - "\\Network Interface(*)\\Packets Sent/sec", - "\\Network Interface(*)\\Packets Received/sec", - "\\Network Interface(*)\\Packets Outbound Errors", - "\\Network Interface(*)\\Packets Received Errors" - ], - "name": "perfCounterDataSource60" - } - ], - "windowsEventLogs": [ - { - "name": "SecurityAuditEvents", - "streams": [ - "Microsoft-Event" - ], - "xPathQueries": [ - "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" - ] - } - ] - }, - "destinations": { - "logAnalytics": [ - { - "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", - "name": "[variables('dcrLogAnalyticsDestinationName')]" - } - ] - }, - "dataFlows": [ - { - "streams": [ - "Microsoft-Perf" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Perf" - }, - { - "streams": [ - "Microsoft-Event" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Event" - } - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2441324888126124697" - }, - "name": "Data Collection Rules", - "description": "This module deploys a Data Collection Rule." - }, - "definitions": { - "dataCollectionRulePropertiesType": { - "type": "object", - "discriminator": { - "propertyName": "kind", - "mapping": { - "Linux": { - "$ref": "#/definitions/linuxDcrPropertiesType" - }, - "Windows": { - "$ref": "#/definitions/windowsDcrPropertiesType" - }, - "All": { - "$ref": "#/definitions/allPlatformsDcrPropertiesType" - }, - "AgentSettings": { - "$ref": "#/definitions/agentSettingsDcrPropertiesType" - }, - "Direct": { - "$ref": "#/definitions/directDcrPropertiesType" - }, - "WorkspaceTransforms": { - "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" - }, - "PlatformTelemetry": { - "$ref": "#/definitions/platformTelemetryDcrPropertiesType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." - } - }, - "linuxDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Linux" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + "__bicep_export!": true, + "description": "The type describing the gallery application that should be made available to the VM/VMSS." + } }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Linux' data collection rule." - } - }, - "windowsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Windows" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + "additionalUnattendContentType": { + "type": "object", + "properties": { + "settingName": { + "type": "string", + "allowedValues": [ + "AutoLogon", + "FirstLogonCommands" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the setting to which the content applies." + } + }, + "content": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." + } }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "winRMListenerType": { + "type": "object", + "properties": { + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Http", + "Https" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the protocol of WinRM listener." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a Windows Remote Management listener." + } }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "nicConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NIC configuration." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "Required. List of IP configurations of the NIC configuration." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the network interface configuration output." + } }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + "extensionCustomScriptConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." + } + }, + "typeHandlerVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "protectedSettings": { + "type": "secureObject", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." + } + }, + "storageAccountName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." + } + }, + "storageAccountKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The access key of the storage account." + } + }, + "managedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "supressFailures": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a 'CustomScriptExtension' extension." + } }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Windows' data collection rule." - } - }, - "allPlatformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "All" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + "_1.applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "_1.applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "_1.backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + "_1.inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the data collection rule of the kind 'All'." - } - }, - "agentSettingsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "AgentSettings" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "agentSettings": { - "$ref": "#/definitions/agentSettingsType", - "metadata": { - "description": "Required. Agent settings used to modify agent behavior on a given host." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'AgentSettings' data collection rule." - } - }, - "agentSettingsType": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "$ref": "#/definitions/agentSettingType" - }, - "metadata": { - "description": "Required. All the settings that are applicable to the logs agent (AMA)." - } - } - }, - "metadata": { - "description": "The type for the agent settings." - } - }, - "agentSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "MaxDiskQuotaInMB", - "UseTimeReceivedForForwardedEvents" - ], - "metadata": { - "description": "Required. The name of the agent setting." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. The value of the agent setting." - } - } - }, - "metadata": { - "description": "The type for the (single) agent setting." - } - }, - "directDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Direct" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "_1.subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "_2.ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + "_2.dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } }, - "description": "Required. Declaration of custom streams used in this rule." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Direct' data collection rule." - } - }, - "workspaceTransformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "WorkspaceTransforms" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "_2.ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } }, - "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + "_3.diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." - } - }, - "platformTelemetryDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "PlatformTelemetry" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "dataSources": { - "type": "object", - "properties": { - "platformTelemetry": { - "type": "array", + "_3.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_4.publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/_3.lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/_2.ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/_2.dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } }, - "description": "Required. The list of platform telemetry configurations." - } - } - }, - "metadata": { - "description": "Required. Specification of data sources that will be collected." - } - }, - "destinations": { - "type": "object", - "properties": { - "logAnalytics": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } }, - "description": "Optional. The list of Log Analytics destinations." + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } }, - "nullable": true - }, - "storageAccounts": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + "description": "The type for the public IP address configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The list of Storage Account destinations." + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, - "nullable": true - }, - "eventHubs": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/_4.publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true }, - "description": "Optional. The list of Event Hub destinations." + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } }, - "nullable": true - } - }, - "metadata": { - "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + "metadata": { + "description": "The type for the IP configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } }, - "description": "Required. The specification of data flows." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the data collection rule. The name is case insensitive." - } - }, - "dataCollectionRuleProperties": { - "$ref": "#/definitions/dataCollectionRulePropertiesType", - "metadata": { - "description": "Required. The kind of data collection rule." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "dataCollectionRule": { - "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "kind": "[parameters('dataCollectionRuleProperties').kind]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRuleAll": { - "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRule_conditionalScopeLock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", - "lock": { - "value": "[parameters('lock')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2876136109547890997" - } - }, - "definitions": { "lockType": { "type": "object", "properties": { @@ -15460,38 +7215,638 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." } }, - "kind": { + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "description": "The type for the network interface IP configuration output.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { "type": "string", "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. The principal type of the assigned principal ID." } }, - "notes": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" } } } }, "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" + }, + "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." + }, + "nullable": true + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" + }, + "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." + }, + "nullable": true + }, + "plan": { + "$ref": "#/definitions/planType", + "nullable": true, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "type": "array", + "items": { + "$ref": "#/definitions/dataDiskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "hibernationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables hibernation capability on the VM." + } + }, + "adminUsername": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." + } + }, + "userData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "items": { + "$ref": "#/definitions/vaultSecretGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "Deallocate", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "publicKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/publicKeyType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "galleryApplications": { + "type": "array", + "items": { + "$ref": "#/definitions/vmGalleryApplicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." + } + }, + "availabilityZone": { + "type": "int", + "allowedValues": [ + -1, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." + } + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationType" + }, + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Recovery service vault name to add VMs to backup." + } + }, + "backupVaultResourceGroup": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "DefaultPolicy", + "metadata": { + "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + } + }, + "autoShutdownConfig": { + "$ref": "#/definitions/autoShutDownConfigType", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for auto-shutdown." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource Id of a maintenance configuration for this VM." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "dataCollectionRuleAssociations": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "$ref": "#/definitions/extensionCustomScriptConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionHostPoolRegistration": { + "type": "secureObject", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "extensionGuestConfigurationExtension": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "guestConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." + } + }, + "extensionGuestConfigurationExtensionProtectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, "lock": { "$ref": "#/definitions/lockType", "nullable": true, @@ -15499,212 +7854,255 @@ "description": "Optional. The lock settings of the service." } }, - "dataCollectionRuleName": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + "description": "Optional. Array of role assignments to create." } - } - }, - "resources": { - "dataCollectionRule": { - "existing": true, - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('dataCollectionRuleName')]" }, - "dataCollectionRule_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "disablePasswordAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether password authentication should be disabled." } - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - }, - "dataCollectionRule_roleAssignments": { - "copy": { - "name": "dataCollectionRule_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", - "name": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "14634305923902101494" }, - "name": "Resource-scoped role assignment", - "description": "This module deploys a Role Assignment for a specific resource." - }, - "parameters": { - "resourceId": { + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], "metadata": { - "description": "Required. The scope for the role assignment, fully qualified resourceId." + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." } }, - "name": { + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { "type": "string", - "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], "metadata": { - "description": "Optional. The unique guid name for the role assignment." + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." } }, - "roleDefinitionId": { + "patchAssessmentMode": { "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "enableHotpatching": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The role definition ID for the role assignment." + "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." } }, - "roleName": { + "timeZone": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. The name for the role, used for logging." + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." } }, - "principalId": { - "type": "string", + "additionalUnattendContent": { + "type": "array", + "items": { + "$ref": "#/definitions/additionalUnattendContentType" + }, + "nullable": true, "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." } }, - "principalType": { + "winRMListeners": { + "type": "array", + "items": { + "$ref": "#/definitions/winRMListenerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." + } + }, + "configurationProfile": { "type": "string", "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." } }, - "description": { + "capacityReservationGroupResourceId": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. The description of role assignment." + "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "networkAccessPolicy": { + "type": "string", + "defaultValue": "DenyAll", + "allowedValues": [ + "AllowAll", + "AllowPrivate", + "DenyAll" + ], "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Policy for accessing the disk via network." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Policy for controlling export on the disk." } } }, "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string" - }, - "name": { - "type": "string" - }, - "roleDefinitionId": { - "type": "string" - }, - "principalId": { - "type": "string" - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string" + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" } }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "principalType": "[[parameters('principalType')]", - "description": "[[parameters('description')]" - } - } - ], - "outputs": { - "roleAssignmentId": { - "type": "string", - "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + { + "name": "additionalUnattendContentFormatted", + "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", + "input": { + "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", + "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", + "componentName": "Microsoft-Windows-Shell-Setup", + "passName": "OobeSystem" } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } - } + ], + "enableReferencedModulesTelemetry": false, + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", + "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" + }, + "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", + "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" }, - "resources": [ - { + "resources": { + "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -15712,2135 +8110,6082 @@ "contentVersion": "1.0.0.0", "resources": [], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "managedDataDisks": { + "copy": { + "name": "managedDataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" + }, + "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", + "type": "Microsoft.Compute/disks", + "apiVersion": "2025-01-02", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", + "location": "[parameters('location')]", + "sku": { + "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" + }, + "properties": { + "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", + "creationData": { + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" + }, + "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", + "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "networkAccessPolicy": "[parameters('networkAccessPolicy')]" + }, + "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", + "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", + "plan": "[parameters('plan')]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", + "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", + "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", + "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", + "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", + "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", + "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", + "osType": "[parameters('osType')]", + "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", + "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", + "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", + "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", + "managedDisk": { + "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", + "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", + "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", + "hibernationEnabled": "[parameters('hibernationEnabled')]" + }, + "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" + } + } + ] + }, + "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", + "licenseType": "[parameters('licenseType')]", + "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" + }, + "dependsOn": [ + "managedDataDisks", + "vm_nic" + ] + }, + "vm_configurationAssignment": { + "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", + "type": "Microsoft.Maintenance/configurationAssignments", + "apiVersion": "2023-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[format('{0}assignment', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", + "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_autoShutdownConfiguration": { + "condition": "[not(empty(parameters('autoShutdownConfig')))]", + "type": "Microsoft.DevTestLab/schedules", + "apiVersion": "2018-09-15", + "name": "[format('shutdown-computevm-{0}', parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", + "properties": { + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", + "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "taskType": "ComputeVmShutdownTask", + "dailyRecurrence": { + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" + }, + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_dataCollectionRuleAssociations": { + "copy": { + "name": "vm_dataCollectionRuleAssociations", + "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" + }, + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2024-03-11", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", + "properties": { + "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "cseIdentity": { + "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", + "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" + }, + "AzureWindowsBaseline": { + "condition": "[not(empty(parameters('guestConfiguration')))]", + "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", + "apiVersion": "2024-04-05", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", + "location": "[parameters('location')]", + "properties": { + "guestConfiguration": "[parameters('guestConfiguration')]" + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + }, + "vm_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_roleAssignments": { + "copy": { + "name": "vm_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" + }, + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" + }, + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" + }, + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "lock": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "5982155361487304817" + } + }, + "definitions": { + "publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the public IP address configuration." + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the IP configuration." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" + }, + "enableTelemetry": { + "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" + }, + "ipTags": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5349747633189946992" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" + }, + "description": "Optional. The public IP address allocation method." + }, + "defaultValue": "Static" + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" + }, + "description": "Optional. IP address version." + }, + "defaultValue": "IPv4" + }, + "dnsSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" + }, + "description": "Optional. The DNS settings of the public IP address." + }, + "nullable": true + }, + "ipTags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" + }, + "description": "Optional. The list of tags associated with the public IP address." + }, + "nullable": true + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" + }, + "description": "Optional. Name of a public IP address SKU." + }, + "defaultValue": "Standard" + }, + "skuTier": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" + }, + "description": "Optional. Tier of a public IP address SKU." + }, + "defaultValue": "Regional" + }, + "ddosSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" + }, + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + }, + "nullable": true + }, + "deleteOption": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" + }, + "description": "Optional. The delete option for the public IP address." + }, + "nullable": true + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "272838238520810437" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface." + }, + "definitions": { + "networkInterfaceIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of load balancer backend address pools." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of references of LoadBalancerInboundNatRules." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the IP configuration is included." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Application Gateway Backend Address Pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The reference to gateway load balancer frontend IP." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Virtual Network Taps." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The resource ID of the deployed resource." + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backend address pool." + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application security group." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application gateway backend address pool." + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the sub resource." + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the inbound NAT rule." + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network tap." + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network interface IP configuration output." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationType" + }, + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "publicIp": { + "copy": { + "name": "publicIp", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", + "existing": true, + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", + "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", + "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", + "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", + "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", + "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", + "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", + "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2024-05-01', 'full').location]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "copy": { + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", + "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", + "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" + } + } + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the network interface." + }, + "value": "[reference('networkInterface').outputs.name.value]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "value": "[reference('networkInterface').outputs.ipConfigurations.value]" } } } } }, - { + "vm_domainJoinExtension": { + "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", "properties": { - "mode": "Incremental", "expressionEvaluationOptions": { - "scope": "Outer" + "scope": "inner" }, - "template": "[variables('$fxv#0')]", + "mode": "Incremental", "parameters": { - "scope": { - "value": "[parameters('resourceId')]" + "virtualMachineName": { + "value": "[parameters('name')]" }, "name": { - "value": "[parameters('name')]" + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" }, - "roleDefinitionId": { - "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + "location": { + "value": "[parameters('location')]" }, - "principalId": { - "value": "[parameters('principalId')]" + "publisher": { + "value": "Microsoft.Compute" }, - "principalType": { - "value": "[parameters('principalType')]" + "type": { + "value": "JsonADDomainExtension" }, - "description": { - "value": "[parameters('description')]" + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } } - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[parameters('name')]" - }, - "roleName": { - "type": "string", - "metadata": { - "description": "The name for the role, used for logging." - }, - "value": "[parameters('roleName')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the dataCollectionRule was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" - }, - "endpoints": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", - "output": true - }, - "description": "The endpoints of the dataCollectionRule, if created." - }, - "nullable": true, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" - }, - "immutableId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The ImmutableId of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmPrivateDnsZones": { - "copy": { - "name": "avmPrivateDnsZones", - "count": "[length(variables('privateDnsZones'))]", - "mode": "serial", - "batchSize": 5 - }, - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZones')[copyIndex()]]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "virtualNetworkLinks": { - "value": [ - { - "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18337341331267624582" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone." - }, - "definitions": { - "aType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" - }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the A record." - } - }, - "aaaaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the AAAA record." - } - }, - "cnameType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. The CNAME record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the CNAME record." - } - }, - "mxType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the MX record." - } - }, - "ptrType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the PTR record." - } - }, - "soaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "soaRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" - }, - "description": "Optional. The SOA record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SOA record." - } - }, - "srvType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "srvRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" - }, - "description": "Optional. The list of SRV records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SRV record." - } - }, - "txtType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "txtRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the TXT record." - } - }, - "virtualNetworkLinkType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 1, - "maxLength": 80, - "metadata": { - "description": "Optional. The resource name." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the virtual network to link." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Region where the resource lives." - } - }, - "registrationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_domainJoinExtension" + ] }, - "description": "Optional. Resource tags." - }, - "nullable": true - }, - "resolutionPolicy": { - "type": "string", - "allowedValues": [ - "Default", - "NxDomainRedirect" - ], - "nullable": true, - "metadata": { - "description": "Optional. The resolution type of the private-dns-zone fallback machanism." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network link." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "a": { - "type": "array", - "items": { - "$ref": "#/definitions/aType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of A records." - } - }, - "aaaa": { - "type": "array", - "items": { - "$ref": "#/definitions/aaaaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of AAAA records." - } - }, - "cname": { - "type": "array", - "items": { - "$ref": "#/definitions/cnameType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of CNAME records." - } - }, - "mx": { - "type": "array", - "items": { - "$ref": "#/definitions/mxType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of MX records." - } - }, - "ptr": { - "type": "array", - "items": { - "$ref": "#/definitions/ptrType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of PTR records." - } - }, - "soa": { - "type": "array", - "items": { - "$ref": "#/definitions/soaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SOA records." - } - }, - "srv": { - "type": "array", - "items": { - "$ref": "#/definitions/srvType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SRV records." - } - }, - "txt": { - "type": "array", - "items": { - "$ref": "#/definitions/txtType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of TXT records." - } - }, - "virtualNetworkLinks": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkLinkType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_roleAssignments": { - "copy": { - "name": "privateDnsZone_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_A": { - "copy": { - "name": "privateDnsZone_A", - "count": "[length(coalesce(parameters('a'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" - }, - "aRecords": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7372385900111002873" + "vm_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] }, - "name": "Private DNS Zone A record", - "description": "This module deploys a Private DNS Zone A record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" } }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } + } + }, + "dependsOn": [ + "vm", + "vm_microsoftAntiMalwareExtension" + ] + }, + "vm_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, + "settings": { + "value": { + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" } }, - "condition": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } + } + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "vm_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the A record." - } - }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" - }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "vm", + "vm_dependencyAgentExtension" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "A": { - "type": "Microsoft.Network/privateDnsZones/A", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aRecords": "[parameters('aRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "A_roleAssignments": { - "copy": { - "name": "A_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "A" + "vm", + "vm_networkWatcherAgentExtension" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed A record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed A record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed A record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_AAAA": { - "copy": { - "name": "privateDnsZone_AAAA", - "count": "[length(coalesce(parameters('aaaa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" - }, - "aaaaRecords": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14405855828972373002" }, - "name": "Private DNS Zone AAAA record", - "description": "This module deploys a Private DNS Zone AAAA record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_customScriptExtension": { + "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" + }, + "provisionAfterExtensions": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettingsFromKeyVault": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" + }, + "settings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" + }, + "protectedSettings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the AAAA record." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "cseIdentity", + "vm" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "AAAA": { - "type": "Microsoft.Network/privateDnsZones/AAAA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aaaaRecords": "[parameters('aaaaRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "AAAA_roleAssignments": { - "copy": { - "name": "AAAA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "AAAA" + "vm", + "vm_customScriptExtension" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AAAA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed AAAA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed AAAA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_CNAME": { - "copy": { - "name": "privateDnsZone_CNAME", - "count": "[length(coalesce(parameters('cname'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" - }, - "cnameRecord": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13818627461335065928" }, - "name": "Private DNS Zone CNAME record", - "description": "This module deploys a Private DNS Zone CNAME record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the CNAME record." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. A CNAME record." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_hostPoolRegistrationExtension": { + "condition": "[parameters('extensionHostPoolRegistration').enabled]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.PowerShell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", + "properties": { + "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", + "aadJoin": true + } + } + }, + "protectedSettings": { + "value": { + "properties": { + "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" + } + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "CNAME": { - "type": "Microsoft.Network/privateDnsZones/CNAME", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "cnameRecord": "[parameters('cnameRecord')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "CNAME_roleAssignments": { - "copy": { - "name": "CNAME_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "CNAME" + "vm", + "vm_nvidiaGpuDriverWindowsExtension" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed CNAME record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed CNAME record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed CNAME record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_MX": { - "copy": { - "name": "privateDnsZone_MX", - "count": "[length(coalesce(parameters('mx'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" - }, - "mxRecords": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2977624679479439942" }, - "name": "Private DNS Zone MX record", - "description": "This module deploys a Private DNS Zone MX record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", + "vm_azureGuestConfigurationExtension": { + "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.GuestConfiguration" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, + "protectedSettings": { + "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the MX record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "vm", + "vm_hostPoolRegistrationExtension" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_backup": { + "condition": "[not(empty(parameters('backupVaultName')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('backupVaultResourceGroup')]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyId": { + "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + }, + "protectedItemType": { + "value": "Microsoft.Compute/virtualMachines" + }, + "protectionContainerName": { + "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "recoveryVaultName": { + "value": "[parameters('backupVaultName')]" + }, + "sourceResourceId": { + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17448691641471706096" + }, + "name": "Recovery Service Vaults Protection Container Protected Item", + "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "protectionContainerName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + } + }, + "recoveryVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "protectedItemType": { + "type": "string", + "allowedValues": [ + "AzureFileShareProtectedItem", + "AzureVmWorkloadSAPAseDatabase", + "AzureVmWorkloadSAPHanaDatabase", + "AzureVmWorkloadSQLDatabase", + "DPMProtectedItem", + "GenericProtectedItem", + "MabFileFolderProtectedItem", + "Microsoft.ClassicCompute/virtualMachines", + "Microsoft.Compute/virtualMachines", + "Microsoft.Sql/servers/databases" + ], + "metadata": { + "description": "Required. The backup item type." + } + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Required. ID of the backup policy with which this item is backed up." + } + }, + "sourceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource to back up." + } + } + }, + "resources": [ + { + "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", + "apiVersion": "2025-02-01", + "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "protectedItemType": "[parameters('protectedItemType')]", + "policyId": "[parameters('policyId')]", + "sourceResourceId": "[parameters('sourceResourceId')]" + } + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the protected item was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the protected item." + }, + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The Name of the protected item." + }, + "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "MX": { - "type": "Microsoft.Network/privateDnsZones/MX", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "mxRecords": "[parameters('mxRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "MX_roleAssignments": { - "copy": { - "name": "MX_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "MX" + "vm", + "vm_azureGuestConfigurationExtension" ] } }, @@ -17848,65 +14193,123 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed MX record." + "description": "The name of the VM." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed MX record." + "description": "The resource ID of the VM." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed MX record." + "description": "The name of the resource group the VM was created in." }, "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2024-07-01', 'full').location]" + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationOutputType" + }, + "metadata": { + "description": "The list of NIC configurations of the virtual machine." + }, + "copy": { + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", + "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" + } + } } } } }, "dependsOn": [ - "privateDnsZone" + "logAnalyticsWorkspace", + "maintenanceConfiguration", + "virtualNetwork", + "windowsVmDataCollectionRules" ] }, - "privateDnsZone_PTR": { - "copy": { - "name": "privateDnsZone_PTR", - "count": "[length(coalesce(parameters('ptr'), createArray()))]" - }, + "maintenanceConfiguration": { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + "value": "[format('mc-{0}', variables('jumpboxVmName'))]" }, - "metadata": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "ptrRecords": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + "extensionProperties": { + "value": { + "InGuestPatchMode": "User" + } }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + "maintenanceScope": { + "value": "InGuestPatch" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + "maintenanceWindow": { + "value": { + "startDateTime": "2024-06-16 00:00", + "duration": "03:55", + "timeZone": "W. Europe Standard Time", + "recurEvery": "1Day" + } }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "visibility": { + "value": "Custom" + }, + "installPatches": { + "value": { + "rebootSetting": "IfRequired", + "windowsParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + }, + "linuxParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + } + } } }, "template": { @@ -17917,303 +14320,49 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "15286275176817336979" + "templateHash": "14895287194406877557" }, - "name": "Private DNS Zone PTR record", - "description": "This module deploys a Private DNS Zone PTR record." + "name": "Maintenance Configurations", + "description": "This module deploys a Maintenance Configuration." }, "definitions": { - "roleAssignmentType": { + "lockType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. Specify the name of lock." } }, - "conditionVersion": { + "kind": { "type": "string", "allowedValues": [ - "2.0" + "CanNotDelete", + "None", + "ReadOnly" ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Specify the type of lock." } }, - "delegatedManagedIdentityResourceId": { + "notes": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the PTR record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "PTR": { - "type": "Microsoft.Network/privateDnsZones/PTR", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ptrRecords": "[parameters('ptrRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "PTR_roleAssignments": { - "copy": { - "name": "PTR_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "PTR" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed PTR record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed PTR record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed PTR record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SOA": { - "copy": { - "name": "privateDnsZone_SOA", - "count": "[length(coalesce(parameters('soa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" - }, - "soaRecord": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4837447718856535826" - }, - "name": "Private DNS Zone SOA record", - "description": "This module deploys a Private DNS Zone SOA record." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -18285,56 +14434,74 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "privateDnsZoneName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + "description": "Required. Maintenance Configuration Name." } }, - "name": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. The name of the SOA record." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "metadata": { + "extensionProperties": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" }, - "description": "Optional. The metadata attached to the record set." + "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." }, - "nullable": true + "defaultValue": {} }, - "soaRecord": { - "type": "object", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "maintenanceScope": { + "type": "string", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" }, - "description": "Optional. A SOA record." + "description": "Optional. Gets or sets maintenanceScope of the configuration." }, - "nullable": true + "defaultValue": "Host" }, - "ttl": { - "type": "int", - "defaultValue": 3600, + "maintenanceWindow": { + "type": "object", "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" + }, + "description": "Optional. Definition of a MaintenanceWindow." + }, + "defaultValue": {} }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "namespace": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Gets or sets namespace of the resource." } }, "roleAssignments": { @@ -18346,6 +14513,36 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" + }, + "description": "Optional. Gets or sets tags of the resource." + }, + "nullable": true + }, + "visibility": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" + }, + "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." + }, + "nullable": true + }, + "installPatches": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" + }, + "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." + }, + "defaultValue": {} } }, "variables": { @@ -18358,11 +14555,10 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -18370,8 +14566,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -18387,31 +14583,44 @@ } } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SOA": { - "type": "Microsoft.Network/privateDnsZones/SOA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "maintenanceConfiguration": { + "type": "Microsoft.Maintenance/maintenanceConfigurations", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "metadata": "[parameters('metadata')]", - "soaRecord": "[parameters('soaRecord')]", - "ttl": "[parameters('ttl')]" + "extensionProperties": "[parameters('extensionProperties')]", + "maintenanceScope": "[parameters('maintenanceScope')]", + "maintenanceWindow": "[parameters('maintenanceWindow')]", + "namespace": "[parameters('namespace')]", + "visibility": "[parameters('visibility')]", + "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" } }, - "SOA_roleAssignments": { + "maintenanceConfiguration_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + }, + "maintenanceConfiguration_roleAssignments": { "copy": { - "name": "SOA_roleAssignments", + "name": "maintenanceConfiguration_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -18422,7 +14631,7 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "SOA" + "maintenanceConfiguration" ] } }, @@ -18430,65 +14639,162 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed SOA record." + "description": "The name of the Maintenance Configuration." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed SOA record." + "description": "The resource ID of the Maintenance Configuration." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed SOA record." + "description": "The name of the resource group the Maintenance Configuration was created in." }, "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the Maintenance Configuration was created in." + }, + "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" } } } - }, - "dependsOn": [ - "privateDnsZone" - ] + } }, - "privateDnsZone_SRV": { - "copy": { - "name": "privateDnsZone_SRV", - "count": "[length(coalesce(parameters('srv'), createArray()))]" - }, + "windowsVmDataCollectionRules": { + "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + "value": "[variables('dataCollectionRulesResourceName')]" }, - "srvRecords": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + "tags": { + "value": "[parameters('tags')]" }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + "location": { + "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "dataCollectionRuleProperties": { + "value": { + "kind": "Windows", + "dataSources": { + "performanceCounters": [ + { + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Processes", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Handle Count", + "\\System\\System Up Time", + "\\System\\Context Switches/sec", + "\\System\\Processor Queue Length", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pages/sec", + "\\Memory\\Page Faults/sec", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors" + ], + "name": "perfCounterDataSource60" + } + ], + "windowsEventLogs": [ + { + "name": "SecurityAuditEvents", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" + ] + } + ] + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", + "name": "[variables('dcrLogAnalyticsDestinationName')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Microsoft-Perf" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Perf" + }, + { + "streams": [ + "Microsoft-Event" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Event" + } + ] + } } }, "template": { @@ -18499,303 +14805,573 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "15028912535488490265" + "templateHash": "2441324888126124697" }, - "name": "Private DNS Zone SRV record", - "description": "This module deploys a Private DNS Zone SRV record." + "name": "Data Collection Rules", + "description": "This module deploys a Data Collection Rule." }, "definitions": { - "roleAssignmentType": { + "dataCollectionRulePropertiesType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Linux": { + "$ref": "#/definitions/linuxDcrPropertiesType" + }, + "Windows": { + "$ref": "#/definitions/windowsDcrPropertiesType" + }, + "All": { + "$ref": "#/definitions/allPlatformsDcrPropertiesType" + }, + "AgentSettings": { + "$ref": "#/definitions/agentSettingsDcrPropertiesType" + }, + "Direct": { + "$ref": "#/definitions/directDcrPropertiesType" + }, + "WorkspaceTransforms": { + "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" + }, + "PlatformTelemetry": { + "$ref": "#/definitions/platformTelemetryDcrPropertiesType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." + } + }, + "linuxDcrPropertiesType": { "type": "object", "properties": { - "name": { + "kind": { "type": "string", - "nullable": true, + "allowedValues": [ + "Linux" + ], "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Required. The kind of the resource." } }, - "roleDefinitionIdOrName": { - "type": "string", + "dataSources": { + "type": "object", "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." } }, - "principalId": { - "type": "string", + "dataFlows": { + "type": "array", "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." } }, - "principalType": { + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." } }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Linux' data collection rule." + } + }, + "windowsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Windows" + ], + "metadata": { + "description": "Required. The kind of the resource." } }, - "condition": { + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." } }, - "conditionVersion": { + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'Windows' data collection rule." + } + }, + "allPlatformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { "type": "string", "allowedValues": [ - "2.0" + "All" ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." } }, - "delegatedManagedIdentityResourceId": { + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Description of the data collection rule." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + "description": "The type for the properties of the data collection rule of the kind 'All'." } }, - "name": { - "type": "string", + "agentSettingsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AgentSettings" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "agentSettings": { + "$ref": "#/definitions/agentSettingsType", + "metadata": { + "description": "Required. Agent settings used to modify agent behavior on a given host." + } + } + }, "metadata": { - "description": "Required. The name of the SRV record." + "description": "The type for the properties of the 'AgentSettings' data collection rule." } }, - "metadata": { + "agentSettingsType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agentSettingType" + }, + "metadata": { + "description": "Required. All the settings that are applicable to the logs agent (AMA)." + } + } }, - "nullable": true - }, - "srvRecords": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + "description": "The type for the agent settings." + } + }, + "agentSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "MaxDiskQuotaInMB", + "UseTimeReceivedForForwardedEvents" + ], + "metadata": { + "description": "Required. The name of the agent setting." + } }, - "description": "Optional. The list of SRV records in the record set." + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the agent setting." + } + } }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." + "description": "The type for the (single) agent setting." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "directDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Direct" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Required. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "The type for the properties of the 'Direct' data collection rule." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "workspaceTransformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "WorkspaceTransforms" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + }, + "platformTelemetryDcrPropertiesType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "kind": { + "type": "string", + "allowedValues": [ + "PlatformTelemetry" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "dataSources": { + "type": "object", + "properties": { + "platformTelemetry": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + }, + "description": "Required. The list of platform telemetry configurations." + } + } + }, + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "destinations": { + "type": "object", + "properties": { + "logAnalytics": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + }, + "description": "Optional. The list of Log Analytics destinations." + }, + "nullable": true + }, + "storageAccounts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + }, + "description": "Optional. The list of Storage Account destinations." + }, + "nullable": true + }, + "eventHubs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + }, + "description": "Optional. The list of Event Hub destinations." + }, + "nullable": true } + }, + "metadata": { + "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." } } + }, + "metadata": { + "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SRV": { - "type": "Microsoft.Network/privateDnsZones/SRV", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "srvRecords": "[parameters('srvRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "SRV_roleAssignments": { - "copy": { - "name": "SRV_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "lockType": { + "type": "object", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "dependsOn": [ - "SRV" - ] - } - }, - "outputs": { - "name": { - "type": "string", "metadata": { - "description": "The name of the deployed SRV record." - }, - "value": "[parameters('name')]" + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SRV record." + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The resource group of the deployed SRV record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_TXT": { - "copy": { - "name": "privateDnsZone_TXT", - "count": "[length(coalesce(parameters('txt'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" - }, - "txtRecords": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7641583415110009849" + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "name": "Private DNS Zone TXT record", - "description": "This module deploys a Private DNS Zone TXT record." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -18867,56 +15443,50 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "privateDnsZoneName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + "description": "Required. The name of the data collection rule. The name is case insensitive." } }, - "name": { - "type": "string", + "dataCollectionRuleProperties": { + "$ref": "#/definitions/dataCollectionRulePropertiesType", "metadata": { - "description": "Required. The name of the TXT record." + "description": "Required. The kind of data collection rule." } }, - "metadata": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "ttl": { - "type": "int", - "defaultValue": 3600, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." + "description": "Optional. Location for all Resources." } }, - "txtRecords": { - "type": "array", + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" - }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true + "description": "Optional. The lock settings of the service." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The managed identity definition for this resource." } }, "roleAssignments": { @@ -18928,6 +15498,16 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true } }, "variables": { @@ -18938,22 +15518,24 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", + "enableReferencedModulesTelemetry": false }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -18969,246 +15551,412 @@ } } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" + "dataCollectionRule": { + "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('dataCollectionRuleProperties').kind]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" }, - "TXT": { - "type": "Microsoft.Network/privateDnsZones/TXT", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]", - "txtRecords": "[parameters('txtRecords')]" - } + "dataCollectionRuleAll": { + "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" }, - "TXT_roleAssignments": { - "copy": { - "name": "TXT_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "dataCollectionRule_conditionalScopeLock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", + "lock": { + "value": "[parameters('lock')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2876136109547890997" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "dataCollectionRuleName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + } + } + }, + "resources": { + "dataCollectionRule": { + "existing": true, + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dataCollectionRuleName')]" + }, + "dataCollectionRule_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + } + } + } }, "dependsOn": [ - "TXT" + "dataCollectionRule", + "dataCollectionRuleAll" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed TXT record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed TXT record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed TXT record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "resolutionPolicy": { - "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7392770862892927923" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link." - }, - "parameters": { - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" - }, - "description": "Optional. Tags of the resource." + "dataCollectionRule_roleAssignments": { + "copy": { + "name": "dataCollectionRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "nullable": true - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - }, - "resolutionPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", + "name": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14634305923902101494" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource." + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" } } } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - }, - "resolutionPolicy": "[parameters('resolutionPolicy')]" - } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed virtual network link." + "description": "The name of the dataCollectionRule." }, - "value": "[parameters('name')]" + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed virtual network link." + "description": "The resource ID of the dataCollectionRule." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed virtual network link." + "description": "The name of the resource group the dataCollectionRule was created in." }, "value": "[resourceGroup().name]" }, @@ -19217,183 +15965,54 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" + }, + "endpoints": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", + "output": true + }, + "description": "The endpoints of the dataCollectionRule, if created." + }, + "nullable": true, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" + }, + "immutableId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The ImmutableId of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" } } } }, "dependsOn": [ - "privateDnsZone" + "logAnalyticsWorkspace" ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "logAnalyticsWorkspace": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('logAnalyticsWorkspaceResourceName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "existingLogAnalyticsWorkspaceId": { - "value": "[parameters('existingLogAnalyticsWorkspaceId')]" - }, - "enablePrivateNetworking": { - "value": "[parameters('enablePrivateNetworking')]" - }, - "enableRedundancy": { - "value": "[parameters('enableRedundancy')]" - }, - "replicaLocation": { - "value": "[variables('replicaLocation')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "13200482898648544945" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of Log analytics Workspace" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location for the Resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" - }, - "description": "Optional. Tags to be applied to the resources." + "avmPrivateDnsZones": { + "copy": { + "name": "avmPrivateDnsZones", + "count": "[length(variables('privateDnsZones'))]", + "mode": "serial", + "batchSize": 5 }, - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - } - }, - "existingLogAnalyticsWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Existing Log Analytics Workspace Resource ID" - } - }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable Private Networking for Log Analytics Workspace." - } - }, - "enableRedundancy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable Redundancy for Log Analytics Workspace." - } - }, - "replicaLocation": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The replica location for Log Analytics Workspace, if redundancy is enabled." - } - } - }, - "variables": { - "useExistingWorkspace": "[not(empty(parameters('existingLogAnalyticsWorkspaceId')))]", - "existingLawSubscription": "[if(variables('useExistingWorkspace'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[2], '')]", - "existingLawResourceGroup": "[if(variables('useExistingWorkspace'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[4], '')]", - "existingLawName": "[if(variables('useExistingWorkspace'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[8], '')]" - }, - "resources": { - "existingLogAnalyticsWorkspace": { - "condition": "[variables('useExistingWorkspace')]", - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "subscriptionId": "[variables('existingLawSubscription')]", - "resourceGroup": "[variables('existingLawResourceGroup')]", - "name": "[variables('existingLawName')]" - }, - "logAnalyticsWorkspace": { - "condition": "[not(variables('useExistingWorkspace'))]", + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", + "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -19401,40 +16020,21 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('name')]" + "value": "[variables('privateDnsZones')[copyIndex()]]" }, "tags": { "value": "[parameters('tags')]" }, - "location": { - "value": "[parameters('location')]" - }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "skuName": { - "value": "PerGB2018" - }, - "dataRetention": { - "value": 365 - }, - "features": { - "value": { - "enableLogAccessUsingOnlyResourcePermissions": true - } - }, - "diagnosticSettings": { + "virtualNetworkLinks": { "value": [ { - "useThisWorkspace": true + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" } ] - }, - "dailyQuotaGb": "[if(parameters('enableRedundancy'), createObject('value', '150'), createObject('value', null()))]", - "replication": "[if(parameters('enableRedundancy'), createObject('value', createObject('enabled', true(), 'location', parameters('replicaLocation'))), createObject('value', null()))]", - "publicNetworkAccessForIngestion": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "publicNetworkAccessForQuery": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "dataSources": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('tags', parameters('tags'), 'eventLogName', 'Application', 'eventTypes', createArray(createObject('eventType', 'Error'), createObject('eventType', 'Warning'), createObject('eventType', 'Information')), 'kind', 'WindowsEvent', 'name', 'applicationEvent'), createObject('counterName', '% Processor Time', 'instanceName', '*', 'intervalSeconds', 60, 'kind', 'WindowsPerformanceCounter', 'name', 'windowsPerfCounter1', 'objectName', 'Processor'), createObject('kind', 'IISLogs', 'name', 'sampleIISLog1', 'state', 'OnPremiseEnabled'))), createObject('value', null()))]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -19443,513 +16043,193 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14099489006827800075" + "version": "0.41.2.15936", + "templateHash": "18337341331267624582" }, - "name": "Log Analytics Workspaces", - "description": "This module deploys a Log Analytics Workspace." + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone." }, "definitions": { - "diagnosticSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "useThisWorkspace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "gallerySolutionType": { + "aType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the gallery solutions to be created in the log analytics workspace." - } - }, - "storageInsightsConfigType": { - "type": "object", - "properties": { - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the storage account to be linked." + "description": "Required. The name of the record." } }, - "containers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "items": { - "type": "string" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." }, - "nullable": true, - "metadata": { - "description": "Optional. List of tables to be read by the workspace." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the storage insights configuration." - } - }, - "linkedServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." - } + "nullable": true }, - "writeAccessResourceId": { - "type": "string", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked service." - } - }, - "linkedStorageAccountType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the link." + "description": "Optional. The TTL of the record." } }, - "storageAccountIds": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked storage account." - } - }, - "savedSearchType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "etag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. The category of the saved search. This helps the user to find a saved search faster." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "functionAlias": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The function alias if query serves as a function." - } - }, - "functionParameters": { - "type": "string", "nullable": true, "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. The query expression for the saved search." + "description": "Optional. Array of role assignments to create." } }, - "tags": { + "aRecords": { "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The tags attached to the saved search." - } - }, - "version": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The version number of the query language. The current version is 2 and is the default." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the saved search." - } - }, - "dataExportType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data export." - } - }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, - "metadata": { - "description": "Optional. The destination of the data export." - } - }, - "enable": { - "type": "bool", - "nullable": true, "metadata": { - "description": "Optional. Enable or disable the data export." - } - }, - "tableNames": { - "type": "array", - "items": { - "type": "string" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." }, - "metadata": { - "description": "Required. The list of table names to export." - } + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Properties of the data export." + "description": "The type for the A record." } }, - "dataSourceType": { + "aaaaType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "metadata": { - "description": "Required. The kind of data source." - } - }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the event log to configure when kind is WindowsEvent." - } - }, - "eventTypes": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "intervalSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + "description": "Required. The name of the record." } }, - "state": { - "type": "string", - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "syslogName": { - "type": "string", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." + "description": "Optional. The TTL of the record." } }, - "syslogSeverities": { + "roleAssignments": { "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." + "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", + "aaaaRecords": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The list of AAAA records in the record set." }, "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Properties of the data source." + "description": "The type for the AAAA record." } }, - "tableType": { + "cnameType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the table." + "description": "Required. The name of the record." } }, - "plan": { - "type": "string", - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. The plan for the table." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The restored logs for the table." + "description": "Optional. The TTL of the record." } }, - "schema": { - "$ref": "#/definitions/schemaType", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The schema for the table." + "description": "Optional. Array of role assignments to create." } }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. The CNAME record in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the CNAME record." + } + }, + "mxType": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "description": "Optional. The search results for the table." + "description": "Required. The name of the record." } }, - "retentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "totalRetentionInDays": { + "ttl": { "type": "int", "nullable": true, - "minValue": 4, - "maxValue": 2555, "metadata": { - "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + "description": "Optional. The TTL of the record." } }, "roleAssignments": { @@ -19959,262 +16239,326 @@ }, "nullable": true, "metadata": { - "description": "Optional. The role assignments for the table." + "description": "Optional. Array of role assignments to create." } + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Properties of the custom table." + "description": "The type for the MX record." } }, - "workspaceFeaturesType": { + "ptrType": { "type": "object", "properties": { - "disableLocalAuth": { - "type": "bool", - "nullable": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. Disable Non-EntraID based Auth. Default is true." + "description": "Required. The name of the record." } }, - "enableDataExport": { - "type": "bool", - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. Flag that indicate if data should be exported." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "enableLogAccessUsingOnlyResourcePermissions": { - "type": "bool", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Enable log access using only resource permissions. Default is false." + "description": "Optional. The TTL of the record." } }, - "immediatePurgeDataOn30Days": { - "type": "bool", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Flag that describes if we want to remove the data after 30 days." + "description": "Optional. Array of role assignments to create." } + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Features of the workspace." + "description": "The type for the PTR record." } }, - "workspaceReplicationType": { + "soaType": { "type": "object", "properties": { - "enabled": { - "type": "bool", + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." + "description": "Optional. The TTL of the record." } }, - "location": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." + "description": "Optional. Array of role assignments to create." } + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. The SOA record in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "Replication properties of the workspace." + "description": "The type for the SOA record." } }, - "_1.columnType": { + "srvType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The column name." + "description": "Required. The name of the record." } }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], + "metadata": { + "type": "object", "metadata": { - "description": "Required. The column type." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The column data type logical hint." + "description": "Optional. The TTL of the record." } }, - "description": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The column description." + "description": "Optional. Array of role assignments to create." } }, - "displayName": { - "type": "string", - "nullable": true, + "srvRecords": { + "type": "array", "metadata": { - "description": "Optional. Column display name." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true } }, "metadata": { - "description": "The parameters of the table column.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } + "__bicep_export!": true, + "description": "The type for the SRV record." } }, - "destinationType": { + "txtType": { "type": "object", "properties": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "Required. The destination resource ID." + "description": "Required. The name of the record." } }, - "metaData": { + "metadata": { "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The destination metadata." + "description": "Optional. Array of role assignments to create." } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true } }, "metadata": { - "description": "The data export destination properties.", - "__bicep_imported_from!": { - "sourceTemplate": "data-export/main.bicep" - } + "__bicep_export!": true, + "description": "The type for the TXT record." } }, - "lockType": { + "virtualNetworkLinkType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, + "minLength": 1, + "maxLength": 80, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The resource name." } }, - "kind": { + "virtualNetworkResourceId": { "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Required. The resource ID of the virtual network to link." } }, - "notes": { + "location": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. The Azure Region where the resource lives." } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { + }, + "registrationEnabled": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." } }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Resource tags." }, + "nullable": true + }, + "resolutionPolicy": { + "type": "string", + "allowedValues": [ + "Default", + "NxDomainRedirect" + ], "nullable": true, "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "description": "Optional. The resolution type of the private-dns-zone fallback machanism." } } }, "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "__bicep_export!": true, + "description": "The type for the virtual network link." } }, - "restoredLogsType": { + "lockType": { "type": "object", "properties": { - "sourceTable": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The table to restore data from." + "description": "Optional. Specify the name of lock." } }, - "startRestoreTime": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." + "description": "Optional. Specify the type of lock." } }, - "endRestoreTime": { + "notes": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "The parameters of the restore operation that initiated the table.", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } }, @@ -20289,122 +16633,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "description": "The table schema.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the search job that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } @@ -20413,219 +16642,104 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the Log Analytics workspace." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "allowedValues": [ - "CapacityReservation", - "Free", - "LACluster", - "PerGB2018", - "PerNode", - "Premium", - "Standalone", - "Standard" - ], - "metadata": { - "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." - } - }, - "skuCapacityReservationLevel": { - "type": "int", - "defaultValue": 100, - "minValue": 100, - "maxValue": 5000, - "metadata": { - "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + "description": "Required. Private DNS zone name." } }, - "storageInsightsConfigs": { + "a": { "type": "array", "items": { - "$ref": "#/definitions/storageInsightsConfigType" + "$ref": "#/definitions/aType" }, "nullable": true, "metadata": { - "description": "Optional. List of storage accounts to be read by the workspace." + "description": "Optional. Array of A records." } }, - "linkedServices": { + "aaaa": { "type": "array", "items": { - "$ref": "#/definitions/linkedServiceType" + "$ref": "#/definitions/aaaaType" }, "nullable": true, "metadata": { - "description": "Optional. List of services to be linked." + "description": "Optional. Array of AAAA records." } }, - "linkedStorageAccounts": { + "cname": { "type": "array", "items": { - "$ref": "#/definitions/linkedStorageAccountType" + "$ref": "#/definitions/cnameType" }, "nullable": true, "metadata": { - "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + "description": "Optional. Array of CNAME records." } }, - "savedSearches": { + "mx": { "type": "array", "items": { - "$ref": "#/definitions/savedSearchType" + "$ref": "#/definitions/mxType" }, "nullable": true, "metadata": { - "description": "Optional. Kusto Query Language searches to save." + "description": "Optional. Array of MX records." } }, - "dataExports": { + "ptr": { "type": "array", "items": { - "$ref": "#/definitions/dataExportType" + "$ref": "#/definitions/ptrType" }, "nullable": true, "metadata": { - "description": "Optional. LAW data export instances to be deployed." + "description": "Optional. Array of PTR records." } }, - "dataSources": { + "soa": { "type": "array", "items": { - "$ref": "#/definitions/dataSourceType" + "$ref": "#/definitions/soaType" }, "nullable": true, "metadata": { - "description": "Optional. LAW data sources to configure." + "description": "Optional. Array of SOA records." } }, - "tables": { + "srv": { "type": "array", "items": { - "$ref": "#/definitions/tableType" + "$ref": "#/definitions/srvType" }, "nullable": true, "metadata": { - "description": "Optional. LAW custom tables to be deployed." + "description": "Optional. Array of SRV records." } }, - "gallerySolutions": { + "txt": { "type": "array", "items": { - "$ref": "#/definitions/gallerySolutionType" + "$ref": "#/definitions/txtType" }, "nullable": true, "metadata": { - "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." - } - }, - "onboardWorkspaceToSentinel": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." - } - }, - "dataRetention": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 730, - "metadata": { - "description": "Optional. Number of days data will be retained for." - } - }, - "dailyQuotaGb": { - "type": "string", - "defaultValue": "-1", - "metadata": { - "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." - } - }, - "defaultDataCollectionRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics query." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." - } - }, - "features": { - "$ref": "#/definitions/workspaceFeaturesType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace features." - } - }, - "replication": { - "$ref": "#/definitions/workspaceReplicationType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace replication properties." + "description": "Optional. Array of TXT records." } }, - "diagnosticSettings": { + "virtualNetworkLinks": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingType" + "$ref": "#/definitions/virtualNetworkLinkType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "forceCmkForQuery": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "location": { + "type": "string", + "defaultValue": "global", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. The location of the PrivateDNSZone. Should be global." } }, "roleAssignments": { @@ -20640,13 +16754,17 @@ }, "tags": { "type": "object", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" - }, "description": "Optional. Tags of the resource." - }, - "nullable": true + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } }, "enableTelemetry": { "type": "bool", @@ -20664,149 +16782,67 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", - "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "features": { - "searchVersion": 1, - "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", - "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", - "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", - "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" - }, - "retentionInDays": "[parameters('dataRetention')]", - "workspaceCapping": { - "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" - }, - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "forceCmkForQuery": "[parameters('forceCmkForQuery')]", - "replication": "[parameters('replication')]", - "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" - }, - "identity": "[variables('identity')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" }, - "logAnalyticsWorkspace_diagnosticSettings": { - "copy": { - "name": "logAnalyticsWorkspace_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + } + } }, - "logAnalyticsWorkspace_sentinelOnboarding": { - "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", - "type": "Microsoft.SecurityInsights/onboardingStates", - "apiVersion": "2025-09-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "default", - "properties": {}, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" }, - "logAnalyticsWorkspace_lock": { + "privateDnsZone_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_roleAssignments": { + "privateDnsZone_roleAssignments": { "copy": { - "name": "logAnalyticsWorkspace_roleAssignments", + "name": "privateDnsZone_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -20817,34 +16853,43 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_storageInsightConfigs": { + "privateDnsZone_A": { "copy": { - "name": "logAnalyticsWorkspace_storageInsightConfigs", - "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" + "name": "privateDnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, - "containers": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" + "name": { + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" }, - "tables": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" + "metadata": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -20854,145 +16899,288 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "140290971998938797" + "version": "0.41.2.15936", + "templateHash": "7372385900111002873" }, - "name": "Log Analytics Workspace Storage Insight Configs", - "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } }, "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, "name": { "type": "string", - "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", "metadata": { - "description": "Optional. The name of the storage insights config." + "description": "Required. The name of the A record." } }, - "storageAccountResourceId": { - "type": "string", + "aRecords": { + "type": "array", "metadata": { - "description": "Required. The Azure Resource Manager ID of the storage account resource." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true }, - "containers": { - "type": "array", - "items": { - "type": "string" + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." }, - "nullable": true, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "tables": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The names of the Azure tables that the workspace should read." + "description": "Optional. Array of role assignments to create." } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "workspace": { + "privateDnsZone": { "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "storageinsightconfig": { - "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "containers": "[parameters('containers')]", - "tables": "[parameters('tables')]", - "storageAccount": { - "id": "[parameters('storageAccountResourceId')]", - "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - } + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] } }, "outputs": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed storage insights configuration." + "description": "The name of the deployed A record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[parameters('name')]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group where the storage insight configuration is deployed." + "description": "The resource ID of the deployed A record." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the storage insights configuration." + "description": "The resource group of the deployed A record." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_linkedServices": { + "privateDnsZone_AAAA": { "copy": { - "name": "logAnalyticsWorkspace_linkedServices", - "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + "name": "privateDnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" + }, + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" }, - "resourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" }, - "writeAccessResourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21002,199 +17190,244 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14482465616812596213" + "version": "0.41.2.15936", + "templateHash": "14405855828972373002" }, - "name": "Log Analytics Workspace Linked Services", - "description": "This module deploys a Log Analytics Workspace Linked Service." + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Required. Name of the link." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "resourceId": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "writeAccessResourceId": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + "description": "Required. The name of the AAAA record." } }, - "tags": { - "type": "object", + "aaaaRecords": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The list of AAAA records in the record set." }, "nullable": true - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "linkedService": { - "type": "Microsoft.OperationalInsights/workspaces/linkedServices", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resourceId": "[parameters('resourceId')]", - "writeAccessResourceId": "[parameters('writeAccessResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed linked service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed linked service." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" }, - "resourceGroupName": { - "type": "string", + "metadata": { + "type": "object", "metadata": { - "description": "The resource group where the linked service is deployed." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_linkedStorageAccounts": { - "copy": { - "name": "logAnalyticsWorkspace_linkedStorageAccounts", - "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" - }, - "storageAccountIds": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14864721709229272590" + "nullable": true }, - "name": "Log Analytics Workspace Linked Storage Accounts", - "description": "This module deploys a Log Analytics Workspace Linked Storage Account." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "name": { - "type": "string", - "allowedValues": [ - "Query", - "Alerts", - "CustomLogs", - "AzureWatson" - ], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. Name of the link." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "storageAccountIds": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, + "nullable": true, "metadata": { - "description": "Required. Linked storage accounts resources Ids." + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "linkedStorageAccount": { - "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "storageAccountIds": "[parameters('storageAccountIds')]" + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed linked storage account." + "description": "The name of the deployed AAAA record." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed linked storage account." + "description": "The resource ID of the deployed AAAA record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group where the linked storage account is deployed." + "description": "The resource group of the deployed AAAA record." }, "value": "[resourceGroup().name]" } @@ -21202,52 +17435,43 @@ } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_savedSearches": { + "privateDnsZone_CNAME": { "copy": { - "name": "logAnalyticsWorkspace_savedSearches", - "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + "name": "privateDnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" - }, - "etag": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" - }, - "displayName": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" }, - "category": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" }, - "query": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" - }, - "functionAlias": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" }, - "functionParameters": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "tags": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" }, - "version": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21257,163 +17481,288 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17904092372918022238" + "version": "0.41.2.15936", + "templateHash": "13818627461335065928" }, - "name": "Log Analytics Workspace Saved Searches", - "description": "This module deploys a Log Analytics Workspace Saved Search." + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Required. Name of the saved search." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "displayName": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Display name for the search." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "category": { + "name": { "type": "string", "metadata": { - "description": "Required. Query category." + "description": "Required. The name of the CNAME record." } }, - "query": { - "type": "string", + "cnameRecord": { + "type": "object", "metadata": { - "description": "Required. Kusto Query to be stored." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. A CNAME record." + }, + "nullable": true }, - "tags": { - "type": "array", + "metadata": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The metadata attached to the record set." }, "nullable": true }, - "functionAlias": { - "type": "string", - "defaultValue": "", + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. The function alias if query serves as a function." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "functionParameters": { - "type": "string", - "defaultValue": "", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "version": { - "type": "int", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The version number of the query language." + "description": "Optional. Array of role assignments to create." } - }, - "etag": { - "type": "string", - "defaultValue": "*", - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "savedSearch": { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "etag": "[parameters('etag')]", - "tags": "[coalesce(parameters('tags'), createArray())]", - "displayName": "[parameters('displayName')]", - "category": "[parameters('category')]", - "query": "[parameters('query')]", - "functionAlias": "[parameters('functionAlias')]", - "functionParameters": "[parameters('functionParameters')]", - "version": "[parameters('version')]" + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] } }, "outputs": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed saved search." + "description": "The name of the deployed CNAME record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[parameters('name')]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group where the saved search is deployed." + "description": "The resource ID of the deployed CNAME record." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the deployed saved search." + "description": "The resource group of the deployed CNAME record." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace", - "logAnalyticsWorkspace_linkedStorageAccounts" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_dataExports": { + "privateDnsZone_MX": { "copy": { - "name": "logAnalyticsWorkspace_dataExports", - "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + "name": "privateDnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "workspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" + }, + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" }, - "destination": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "enable": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" }, - "tableNames": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21423,122 +17772,244 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17943947755417749524" + "version": "0.41.2.15936", + "templateHash": "2977624679479439942" }, - "name": "Log Analytics Workspace Data Exports", - "description": "This module deploys a Log Analytics Workspace Data Export." + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." }, "definitions": { - "destinationType": { + "roleAssignmentType": { "type": "object", "properties": { - "resourceId": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The destination resource ID." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The destination metadata." + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The data export destination properties." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } } }, "parameters": { - "name": { + "privateDnsZoneName": { "type": "string", - "minLength": 4, - "maxLength": 63, "metadata": { - "description": "Required. The data export rule name." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "workspaceName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + "description": "Required. The name of the MX record." } }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. Destination properties." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "enable": { + "enableTelemetry": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { - "description": "Optional. Active when enabled." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "tableNames": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, + "nullable": true, "metadata": { - "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + "description": "Optional. Array of role assignments to create." } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "dataExport": { - "type": "Microsoft.OperationalInsights/workspaces/dataExports", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "destination": "[parameters('destination')]", - "enable": "[parameters('enable')]", - "tableNames": "[parameters('tableNames')]" + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the data export." + "description": "The name of the deployed MX record." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the data export." + "description": "The resource ID of the deployed MX record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the data export was created in." + "description": "The resource group of the deployed MX record." }, "value": "[resourceGroup().name]" } @@ -21546,67 +18017,43 @@ } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_dataSources": { + "privateDnsZone_PTR": { "copy": { - "name": "logAnalyticsWorkspace_dataSources", - "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + "name": "privateDnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "logAnalyticsWorkspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" - }, - "kind": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" - }, - "linkedResourceId": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" - }, - "eventLogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" }, - "eventTypes": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" - }, - "objectName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" - }, - "instanceName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" - }, - "intervalSeconds": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" - }, - "counterName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" - }, - "state": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" }, - "syslogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" }, - "syslogSeverities": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "performanceCounters": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" }, - "tags": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21616,227 +18063,288 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "15360290236166491819" + "version": "0.41.2.15936", + "templateHash": "15286275176817336979" }, - "name": "Log Analytics Workspace Datasources", - "description": "This module deploys a Log Analytics Workspace Data Source." + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "name": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Name of the data source." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "kind": { + "name": { "type": "string", - "defaultValue": "AzureActivityLog", - "allowedValues": [ - "AzureActivityLog", - "WindowsEvent", - "WindowsPerformanceCounter", - "IISLogs", - "LinuxSyslog", - "LinuxSyslogCollection", - "LinuxPerformanceObject", - "LinuxPerformanceCollection" - ], "metadata": { - "description": "Optional. The kind of the data source." + "description": "Required. The name of the PTR record." } }, - "tags": { + "metadata": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. The metadata attached to the record set." }, "nullable": true }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the resource to be linked." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Windows event log name to configure when kind is WindowsEvent." - } - }, - "eventTypes": { + "ptrRecords": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Windows event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "defaultValue": "*", "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true }, - "intervalSeconds": { + "ttl": { "type": "int", - "defaultValue": 60, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, + "defaultValue": 3600, "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "syslogName": { - "type": "string", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "syslogSeverities": { + "roleAssignments": { "type": "array", - "defaultValue": [], + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "dataSource": { - "type": "Microsoft.OperationalInsights/workspaces/dataSources", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "kind": "[parameters('kind')]", - "tags": "[parameters('tags')]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", - "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", - "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", - "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", - "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", - "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", - "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", - "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", - "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", - "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", - "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] } }, "outputs": { - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed data source." + "description": "The name of the deployed PTR record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[parameters('name')]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group where the data source is deployed." + "description": "The resource ID of the deployed PTR record." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the deployed data source." + "description": "The resource group of the deployed PTR record." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_tables": { + "privateDnsZone_SOA": { "copy": { - "name": "logAnalyticsWorkspace_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" + "name": "privateDnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "workspaceName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "plan": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" - }, - "schema": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" - }, - "retentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" }, - "totalRetentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" }, - "restoredLogs": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" }, - "searchResults": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -21846,182 +18354,304 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "18383178824663161801" + "version": "0.41.2.15936", + "templateHash": "4837447718856535826" }, - "name": "Log Analytics Workspace Tables", - "description": "This module deploys a Log Analytics Workspace Table." + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." }, "definitions": { - "restoredLogsType": { + "roleAssignmentType": { "type": "object", "properties": { - "sourceTable": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The table to restore data from." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "startRestoreTime": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the restore operation that initiated the table." - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { + "principalId": { "type": "string", "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "description": { + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The table description." + "description": "Optional. The principal type of the assigned principal ID." } }, - "displayName": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The table schema." - } - }, - "columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." + "description": "Optional. The description of the role assignment." } }, - "type": { + "condition": { "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], + "nullable": true, "metadata": { - "description": "Required. The column type." + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "dataTypeHint": { + "conditionVersion": { "type": "string", "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" + "2.0" ], "nullable": true, "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." + "description": "Optional. Version of the condition." } }, - "displayName": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Column display name." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The parameters of the table column." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "searchResultsType": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." + "description": "Optional. A SOA record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The parameters of the search job that initiated the table." - } + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SRV": { + "copy": { + "name": "privateDnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15028912535488490265" }, + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -22099,66 +18729,50 @@ } }, "parameters": { - "name": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. The name of the table." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "workspaceName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + "description": "Required. The name of the SRV record." } }, - "plan": { - "type": "string", - "defaultValue": "Analytics", - "allowedValues": [ - "Basic", - "Analytics" - ], + "metadata": { + "type": "object", "metadata": { - "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, + "srvRecords": { + "type": "array", "metadata": { - "description": "Optional. Restore parameters." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true }, - "retentionInDays": { + "ttl": { "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, - "metadata": { - "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. Table's schema." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, + "defaultValue": 3600, "metadata": { - "description": "Optional. Parameters of the search job that initiated this table." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "totalRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 2555, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + "description": "Optional. Enable/Disable usage telemetry for module." } }, "roleAssignments": { @@ -22182,10 +18796,8 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", @@ -22193,34 +18805,51 @@ } }, "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "table": { - "type": "Microsoft.OperationalInsights/workspaces/tables", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "plan": "[parameters('plan')]", - "restoredLogs": "[parameters('restoredLogs')]", - "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", - "schema": "[parameters('schema')]", - "searchResults": "[parameters('searchResults')]", - "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" } }, - "table_roleAssignments": { + "SRV_roleAssignments": { "copy": { - "name": "table_roleAssignments", + "name": "SRV_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -22231,7 +18860,7 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "table" + "SRV" ] } }, @@ -22239,21 +18868,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the table." + "description": "The name of the deployed SRV record." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the table." + "description": "The resource ID of the deployed SRV record." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the table was created in." + "description": "The resource group of the deployed SRV record." }, "value": "[resourceGroup().name]" } @@ -22261,35 +18890,40 @@ } }, "dependsOn": [ - "logAnalyticsWorkspace" + "privateDnsZone" ] }, - "logAnalyticsWorkspace_solutions": { + "privateDnsZone_TXT": { "copy": { - "name": "logAnalyticsWorkspace_solutions", - "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + "name": "privateDnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" }, - "condition": "[not(empty(parameters('gallerySolutions')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" }, - "location": { - "value": "[parameters('location')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" }, - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "plan": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -22302,75 +18936,163 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "10255889523646649592" + "version": "0.41.2.15936", + "templateHash": "7641583415110009849" }, - "name": "Operations Management Solutions", - "description": "This module deploys an Operations Management Solution.", - "owner": "Azure/module-maintainers" + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." }, "definitions": { - "solutionPlanType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "product": { + "conditionVersion": { "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + "description": "Optional. Version of the condition." } }, - "publisher": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } } }, "parameters": { - "name": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "plan": { - "$ref": "#/definitions/solutionPlanType", + "name": { + "type": "string", "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + "description": "Required. The name of the TXT record." } }, - "logAnalyticsWorkspaceName": { - "type": "string", + "metadata": { + "type": "object", "metadata": { - "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { @@ -22378,7 +19100,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -22388,993 +19110,322 @@ "outputs": { "telemetry": { "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2021-06-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "solution": { - "type": "Microsoft.OperationsManagement/solutions", - "apiVersion": "2015-11-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" - }, - "plan": { - "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", - "promotionCode": "", - "product": "[parameters('plan').product]", - "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed solution." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed solution." - }, - "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the solution is deployed." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('solution', '2015-11-01-preview', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed log analytics workspace." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed log analytics workspace." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed log analytics workspace." - }, - "value": "[parameters('name')]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "The ID associated with the workspace." - }, - "value": "[reference('logAnalyticsWorkspace').customerId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" - }, - "primarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The primary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" - }, - "secondarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The secondary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" - } - } - } - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingLawSubscription'), variables('existingLawResourceGroup')), 'Microsoft.OperationalInsights/workspaces', variables('existingLawName')), reference('logAnalyticsWorkspace').outputs.resourceId.value)]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), reference('existingLogAnalyticsWorkspace').customerId, reference('logAnalyticsWorkspace').outputs.logAnalyticsWorkspaceId.value)]" - }, - "primarySharedKey": { - "type": "securestring", - "value": "[if(variables('useExistingWorkspace'), if(variables('useExistingWorkspace'), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingLawSubscription'), variables('existingLawResourceGroup')), 'Microsoft.OperationalInsights/workspaces', variables('existingLawName')), '2020-08-01'), listOutputsWithSecureValues('logAnalyticsWorkspace', '2025-04-01').primarySharedKey).primarySharedKey, listOutputsWithSecureValues('logAnalyticsWorkspace', '2025-04-01').primarySharedKey)]" - }, - "location": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), reference('existingLogAnalyticsWorkspace', '2025-07-01', 'full').location, reference('logAnalyticsWorkspace').outputs.location.value)]" - }, - "name": { - "type": "string", - "value": "[if(variables('useExistingWorkspace'), variables('existingLawName'), reference('logAnalyticsWorkspace').outputs.name.value)]" - } - } - } - } - }, - "applicationInsights": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appi-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "retentionInDays": { - "value": 365 - }, - "kind": { - "value": "web" - }, - "disableIpMasking": { - "value": false - }, - "flowType": { - "value": "Bluefield" - }, - "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17358780145253914698" - }, - "name": "Application Insights", - "description": "This component deploys an Application Insights instance." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application Insights." - } - }, - "applicationType": { - "type": "string", - "defaultValue": "web", - "allowedValues": [ - "web", - "other" - ], - "metadata": { - "description": "Optional. Application type." - } - }, - "workspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." - } - }, - "disableIpMasking": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable IP masking. Default value is set to true." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." - } - }, - "forceCustomerStorageForProfiler": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Force users to create their own storage account for profiler and debugger." - } - }, - "linkedStorageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Linked storage account resource ID." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": 365, - "allowedValues": [ - 30, - 60, - 90, - 120, - 180, - 270, - 365, - 550, - 730 - ], - "metadata": { - "description": "Optional. Retention period in days." - } - }, - "samplingPercentage": { - "type": "int", - "defaultValue": 100, - "minValue": 0, - "maxValue": 100, - "metadata": { - "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." - } - }, - "flowType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." - } - }, - "requestSource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." - } - }, - "kind": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." - } - }, - "immediatePurgeDataOn30Days": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Purge data immediately after 30 days." - } - }, - "ingestionMode": { - "type": "string", - "nullable": true, - "allowedValues": [ - "ApplicationInsights", - "ApplicationInsightsWithDiagnosticSettings", - "LogAnalytics" - ], - "metadata": { - "description": "Optional. Indicates the flow of the ingestion." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/components@2020-02-02#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", - "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", - "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "appInsights": { - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "Application_Type": "[parameters('applicationType')]", - "DisableIpMasking": "[parameters('disableIpMasking')]", - "DisableLocalAuth": "[parameters('disableLocalAuth')]", - "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", - "WorkspaceResourceId": "[parameters('workspaceResourceId')]", - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "RetentionInDays": "[parameters('retentionInDays')]", - "SamplingPercentage": "[parameters('samplingPercentage')]", - "Flow_Type": "[parameters('flowType')]", - "Request_Source": "[parameters('requestSource')]", - "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", - "IngestionMode": "[parameters('ingestionMode')]" - } - }, - "appInsights_roleAssignments": { - "copy": { - "name": "appInsights_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_diagnosticSettings": { - "copy": { - "name": "appInsights_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "linkedStorageAccount": { - "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appInsightsName": { - "value": "[parameters('name')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5059808225314360251" + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] }, - "name": "Application Insights Linked Storage Account", - "description": "This component deploys an Application Insights Linked Storage Account." + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7392770862892927923" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } }, - "parameters": { - "appInsightsName": { + "outputs": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." - } + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Linked storage account resource ID." - } - } - }, - "resources": [ - { - "type": "microsoft.insights/components/linkedStorageAccounts", - "apiVersion": "2020-03-01-preview", - "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", - "properties": { - "linkedStorageAccount": "[parameters('storageAccountResourceId')]" - } - } - ], - "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the Linked Storage Account." + "description": "The name of the private DNS zone." }, - "value": "ServiceProfiler" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Linked Storage Account." + "description": "The resource ID of the private DNS zone." }, - "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The resource group the agent pool was deployed into." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" } } } }, "dependsOn": [ - "appInsights" + "virtualNetwork" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the application insights component." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application insights component." - }, - "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the application insights component was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "applicationId": { - "type": "string", - "metadata": { - "description": "The application ID of the application insights component." - }, - "value": "[reference('appInsights').AppId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('appInsights', '2020-02-02', 'full').location]" - }, - "instrumentationKey": { - "type": "string", - "metadata": { - "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." - }, - "value": "[reference('appInsights').InstrumentationKey]" - }, - "connectionString": { - "type": "string", - "metadata": { - "description": "Application Insights Connection String." - }, - "value": "[reference('appInsights').ConnectionString]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmManagedIdentity": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('id-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "15729887991536611208" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the managed identity." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Required. The location of the managed identity." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Required. Tags to be applied to the managed identity." - } }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry for the AVM deployment." - } - } - }, - "resources": [ - { + "logAnalyticsWorkspace": { + "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[parameters('name')]", + "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, "name": { - "value": "[parameters('name')]" + "value": "[variables('logAnalyticsWorkspaceResourceName')]" }, "location": { "value": "[parameters('location')]" @@ -23384,6 +19435,12 @@ }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" + }, + "enableReplication": { + "value": "[parameters('enableRedundancy')]" + }, + "replicationLocation": { + "value": "[variables('replicaLocation')]" } }, "template": { @@ -23393,325 +19450,106 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." + "version": "0.42.1.51946", + "templateHash": "9919485194443011422" + } }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, + "parameters": { + "solutionName": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." + "description": "Solution name suffix used to derive the resource name." } }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." } }, - "roleAssignmentType": { + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } + "description": "Tags to apply to the resource." } - } - }, - "parameters": { - "name": { - "type": "string", + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, "metadata": { - "description": "Required. Name of the User Assigned Identity." + "description": "Retention period in days. WAF recommends 365." } }, - "location": { + "skuName": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "PerGB2018", "metadata": { - "description": "Optional. Location for all resources." + "description": "SKU name for the workspace." } }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Public network access for ingestion." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Public network access for query." } }, - "tags": { - "type": "object", + "enableReplication": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true + "description": "Enable workspace replication for redundancy." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "replicationLocation": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Replication location (paired region)." } }, - "isolationScope": { + "dailyQuotaGb": { "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], + "defaultValue": "", "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Data sources for VM monitoring (Windows events, perf counters)." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, + "workspace": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -23719,1075 +19557,3210 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { "value": "[parameters('name')]" }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + "location": { + "value": "[parameters('location')]" }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + "tags": { + "value": "[parameters('tags')]" }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } + "dataRetention": { + "value": "[parameters('retentionInDays')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "diagnosticSettings": { + "value": [ + { + "useThisWorkspace": true + } + ] + }, + "publicNetworkAccessForIngestion": { + "value": "[parameters('publicNetworkAccessForIngestion')]" + }, + "publicNetworkAccessForQuery": { + "value": "[parameters('publicNetworkAccessForQuery')]" + }, + "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", + "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", + "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "1387931959101373036" + "templateHash": "14099489006827800075" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace." + }, + "definitions": { + "diagnosticSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "gallerySolutionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the gallery solutions to be created in the log analytics workspace." + } + }, + "storageInsightsConfigType": { + "type": "object", + "properties": { + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the storage account to be linked." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of tables to be read by the workspace." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the storage insights configuration." + } + }, + "linkedServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked service." + } + }, + "linkedStorageAccountType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked storage account." + } + }, + "savedSearchType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "etag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. The category of the saved search. This helps the user to find a saved search faster." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "functionAlias": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. The query expression for the saved search." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The tags attached to the saved search." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language. The current version is 2 and is the default." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the saved search." + } + }, + "dataExportType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data export." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. The destination of the data export." + } + }, + "enable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the data export." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of table names to export." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data export." + } + }, + "dataSourceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "metadata": { + "description": "Required. The kind of data source." + } + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the event log to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data source." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "plan": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The plan for the table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. The restored logs for the table." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. The schema for the table." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. The search results for the table." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The role assignments for the table." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the custom table." + } }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." + "workspaceFeaturesType": { + "type": "object", + "properties": { + "disableLocalAuth": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable Non-EntraID based Auth. Default is true." + } + }, + "enableDataExport": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that indicate if data should be exported." + } + }, + "enableLogAccessUsingOnlyResourcePermissions": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable log access using only resource permissions. Default is false." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that describes if we want to remove the data after 30 days." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Features of the workspace." + } + }, + "workspaceReplicationType": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Replication properties of the workspace." + } + }, + "_1.columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "description": "The parameters of the table column.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "description": "The data export destination properties.", + "__bicep_imported_from!": { + "sourceTemplate": "data-export/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the restore operation that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "description": "The table schema.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the search job that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" + } + } + } }, "parameters": { - "userAssignedIdentityName": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/storageInsightsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "linkedServices": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedStorageAccountType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + } + }, + "savedSearches": { + "type": "array", + "items": { + "$ref": "#/definitions/savedSearchType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "items": { + "$ref": "#/definitions/dataExportType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "items": { + "$ref": "#/definitions/dataSourceType" + }, + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + "description": "Optional. LAW data sources to configure." } }, - "name": { - "type": "string", + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, "metadata": { - "description": "Required. The name of the secret." + "description": "Optional. LAW custom tables to be deployed." } }, - "audiences": { + "gallerySolutions": { "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." } }, - "issuer": { - "type": "string", + "onboardWorkspaceToSentinel": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." } }, - "subject": { - "type": "string", + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + "description": "Optional. Number of days data will be retained for." } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "-1", + "metadata": { + "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." } - } - ], - "outputs": { - "name": { + }, + "defaultDataCollectionRuleResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "The name of the federated identity credential." - }, - "value": "[parameters('name')]" + "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." + } }, - "resourceId": { + "publicNetworkAccessForIngestion": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], "metadata": { - "description": "The resource ID of the federated identity credential." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } }, - "resourceGroupName": { + "publicNetworkAccessForQuery": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], "metadata": { - "description": "The name of the resource group the federated identity credential was created in." + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "features": { + "$ref": "#/definitions/workspaceFeaturesType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace features." + } + }, + "replication": { + "$ref": "#/definitions/workspaceReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace replication properties." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingType" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "userAssignedIdentity" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', parameters('name')), '2025-04-01').outputs.resourceId.value]" - }, - "principalId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', parameters('name')), '2025-04-01').outputs.principalId.value]" - } - } - } - } - }, - "avmContainerRegistry": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "acrName": { - "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "acrSku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "zoneRedundancy": { - "value": "Disabled" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmContainerRegistryReader').outputs.principalId.value]", - "roleDefinitionIdOrName": "AcrPull", - "principalType": "ServicePrincipal" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableRedundancy": { - "value": "[parameters('enableRedundancy')]" - }, - "replicaLocation": { - "value": "[variables('replicaLocation')]" - }, - "enablePrivateNetworking": { - "value": "[parameters('enablePrivateNetworking')]" - }, - "backendSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", - "privateDnsZoneResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value), createObject('value', ''))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "8672669912945312056" - }, - "name": "Container Registry Module" - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "acrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Azure Container Registry." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Required. The location of the Azure Container Registry." - } - }, - "acrSku": { - "type": "string", - "defaultValue": "Basic", - "metadata": { - "description": "Optional. SKU for the Azure Container Registry." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Optional. Public network access setting for the Azure Container Registry." - } - }, - "zoneRedundancy": { - "type": "string", - "defaultValue": "Disabled", - "metadata": { - "description": "Optional. Zone redundancy setting for the Azure Container Registry." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the Container Registry." - } - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry for the AVM deployment." - } - }, - "enableRedundancy": { - "type": "bool", - "metadata": { - "description": "Required. Enable Redundancy for the AVM deployment." - } - }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. The replica location for the Azure Container Registry replication, if redundancy is enabled." - } - }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable private networking for the Container Registry." - } - }, - "backendSubnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Backend subnet resource ID for private endpoints." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Private DNS zone resource ID for Container Registry." - } - } - }, - "resources": { - "avmContainerRegistry": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[parameters('acrName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('acrName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "acrSku": { - "value": "[parameters('acrSku')]" - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - }, - "zoneRedundancy": { - "value": "[parameters('zoneRedundancy')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "replications": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('location', parameters('replicaLocation'), 'name', format('acrrepl{0}', replace(parameters('replicaLocation'), '-', ''))))), createObject('value', null()))]", - "networkRuleSetDefaultAction": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Deny'), createObject('value', 'Allow'))]", - "networkRuleSetIpRules": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray()), createObject('value', null()))]", - "exportPolicyStatus": "[if(parameters('enablePrivateNetworking'), createObject('value', 'disabled'), createObject('value', null()))]", - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-acr-{0}', parameters('acrName')), 'customNetworkInterfaceName', format('nic-acr-{0}', parameters('acrName')), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceId'))), createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'acr-dns-zone-group', 'privateDnsZoneResourceId', parameters('privateDnsZoneResourceId')))), null()), 'subnetResourceId', parameters('backendSubnetResourceId')))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1509121545318808417" - }, - "name": "Azure Container Registries (ACR)", - "description": "This module deploys an Azure Container Registry (ACR)." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "credentialSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" - }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a credential set." - } - }, - "scopeMapsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the scope map." - } - }, - "actions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" }, - "description": "Required. The list of scoped permissions for registry artifacts." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The user friendly description of the scope map." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a scope map." - } - }, - "cacheRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cache rule." - } - }, - "replicationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true }, - "description": "Optional. Tags of the resource." + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } - }, - "zoneRedundancy": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" - }, - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replication." - } - }, - "taskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the task." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", + "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", + "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", + "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]", + "replication": "[parameters('replication')]", + "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" + }, + "identity": "[variables('identity')]" }, - "description": "Optional. The platform properties for the task." - }, - "nullable": true - }, - "step": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + "logAnalyticsWorkspace_diagnosticSettings": { + "copy": { + "name": "logAnalyticsWorkspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The step properties for the task." - }, - "nullable": true - }, - "trigger": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + "logAnalyticsWorkspace_sentinelOnboarding": { + "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", + "type": "Microsoft.SecurityInsights/onboardingStates", + "apiVersion": "2025-09-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "default", + "properties": {}, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { + "copy": { + "name": "logAnalyticsWorkspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "140290971998938797" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14482465616812596213" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedStorageAccounts": { + "copy": { + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" + }, + "storageAccountIds": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14864721709229272590" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": "[parameters('storageAccountIds')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" + }, + "etag": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + }, + "category": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" + }, + "query": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17904092372918022238" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] }, - "description": "Optional. The trigger properties for the task." - }, - "nullable": true - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17943947755417749524" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The status of the task at the time the operation was called." - }, - "nullable": true - }, - "timeout": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." - } - }, - "agentConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + "logAnalyticsWorkspace_dataSources": { + "copy": { + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" + }, + "kind": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "15360290236166491819" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The agent configuration for the task." - }, - "nullable": true - }, - "agentPoolName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." - } - }, - "isSystemTask": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." - } - }, - "logTemplate": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The log template for the task to use when creating logs in Log Analytics." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a task." - } - }, - "tokenType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the token." - } - }, - "scopeMapResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the scope map which defines the permissions for this token." - } - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "18383178824663161801" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The status of the token at the time the operation was called." - }, - "nullable": true - }, - "credentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10255889523646649592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." - } - } - } - }, - "webhookType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "string", - "metadata": { - "description": "Required. The service URI for the webhook to post notifications." - } - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" }, - "description": "Optional. The status of the webhook at the time the operation was called." - }, - "nullable": true - }, - "action": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "customHeaders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" }, - "description": "Optional. Custom headers that will be added to the webhook notifications." - }, - "nullable": true - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a webhook." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "logAnalyticsWorkspaceId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" }, - "memberName": { + "location": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" }, - "privateIPAddress": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + "description": "The principal ID of the system assigned identity." }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } + "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" + }, + "primarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The primary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" + }, + "secondarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The secondary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } - }, - "authCredentialsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } - }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." - } - }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." }, + "value": "[reference('workspace').outputs.resourceId.value]" + }, + "name": { + "type": "string", "metadata": { - "description": "The type for auth credentials.", - "__bicep_imported_from!": { - "sourceTemplate": "credential-set/main.bicep" - } - } + "description": "Name of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.name.value]" }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." }, + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + } + }, + "applicationInsights": { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appi-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "retentionInDays": { + "value": 365 + }, + "kind": { + "value": "web" + }, + "disableIpMasking": { + "value": false + }, + "flowType": { + "value": "Bluefield" + }, + "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17358780145253914698" }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance." + }, + "definitions": { "diagnosticSettingFullType": { "type": "object", "properties": { @@ -24906,7 +22879,7 @@ "metadata": { "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -24943,904 +22916,2836 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "managedIdentityAllType": { + "roleAssignmentType": { "type": "object", "properties": { - "systemAssigned": { - "type": "bool", + "name": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "flowType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." + } + }, + "requestSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Purge data immediately after 30 days." + } + }, + "ingestionMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ApplicationInsights", + "ApplicationInsightsWithDiagnosticSettings", + "LogAnalytics" + ], + "metadata": { + "description": "Optional. Indicates the flow of the ingestion." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/components@2020-02-02#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]", + "Flow_Type": "[parameters('flowType')]", + "Request_Source": "[parameters('requestSource')]", + "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", + "IngestionMode": "[parameters('ingestionMode')]" + } + }, + "appInsights_roleAssignments": { + "copy": { + "name": "appInsights_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_diagnosticSettings": { + "copy": { + "name": "appInsights_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5059808225314360251" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } } } }, + "dependsOn": [ + "appInsights" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights component was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference('appInsights').AppId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "avmManagedIdentity": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Azure region for the resource." } }, - "managedIdentityOnlySysAssignedType": { + "tags": { "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Tags to apply to the resource." } }, - "privateEndpointSingleServiceType": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('identityName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" + "tags": { + "value": "[parameters('tags')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } } - }, - "parameters": { - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. Name of your Azure Container Registry." - } - }, - "acrAdminUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable admin user that have push / pull permission to the registry." - } - }, - "location": { + ], + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "description": "Resource ID of the managed identity." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "autoGeneratedDomainNameLabelScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse", - "Unsecure" - ], - "metadata": { - "description": "Optional. The domain name label reuse scope." - } + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "roleAssignmentMode": { + "principalId": { "type": "string", - "nullable": true, - "allowedValues": [ - "AbacRepositoryPermissions", - "LegacyRegistryPermissions" - ], "metadata": { - "description": "Optional. The registry permissions role assignment mode." - } + "description": "Principal ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" }, - "acrSku": { + "clientId": { "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Premium", - "Standard" - ], "metadata": { - "description": "Optional. Tier of your Azure container registry." - } + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" }, - "exportPolicyStatus": { + "name": { "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], "metadata": { - "description": "Optional. The value that indicates whether the export policy is enabled or not." - } - }, - "quarantinePolicyStatus": { + "description": "Name of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + "avmContainerRegistry": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "acrPullPrincipalIds": { + "value": [ + "[reference('avmContainerRegistryReader').outputs.principalId.value]" + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8138805991948000285" + } + }, + "parameters": { + "solutionName": { "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], "metadata": { - "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + "description": "Solution name used for naming convention." } }, - "trustPolicyStatus": { + "name": { "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", "metadata": { - "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + "description": "Name of the container registry." } }, - "retentionPolicyStatus": { + "location": { "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the retention policy is enabled or not." - } - }, - "retentionPolicyDays": { - "type": "int", - "defaultValue": 15, "metadata": { - "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + "description": "Azure region for deployment." } }, - "azureADAuthenticationAsArmPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + "description": "Resource tags." } }, - "softDeletePolicyStatus": { + "sku": { "type": "string", - "defaultValue": "disabled", + "defaultValue": "Premium", "allowedValues": [ - "disabled", - "enabled" + "Basic", + "Standard", + "Premium" ], "metadata": { - "description": "Optional. Soft Delete policy status. Default is disabled." - } - }, - "softDeletePolicyDays": { - "type": "int", - "defaultValue": 7, - "metadata": { - "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + "description": "SKU for the container registry." } }, - "dataEndpointEnabled": { + "adminUserEnabled": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + "description": "Enable admin user for the registry." } }, "publicNetworkAccess": { "type": "string", - "nullable": true, + "defaultValue": "Enabled", "allowedValues": [ "Enabled", "Disabled" ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + "description": "Public network access setting." } }, - "networkRuleBypassOptions": { - "type": "string", - "defaultValue": "AzureServices", - "allowedValues": [ - "AzureServices", - "None" - ], - "metadata": { - "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." - } - }, - "networkRuleSetDefaultAction": { + "exportPolicyStatus": { "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], + "defaultValue": "enabled", "metadata": { - "description": "Optional. The default action of allow or deny when no other rules match." + "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." } }, - "networkRuleSetIpRules": { + "acrPullPrincipalIds": { "type": "array", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." + "description": "Principal IDs to assign AcrPull role." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + "description": "Enable private networking." } }, - "zoneRedundancy": { + "privateEndpointSubnetId": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } - }, - "replications": { - "type": "array", - "items": { - "$ref": "#/definitions/replicationType" - }, - "nullable": true, + "defaultValue": "", "metadata": { - "description": "Optional. All replications to create." + "description": "Subnet resource ID for private endpoint." } }, - "webhooks": { + "privateDnsZoneResourceIds": { "type": "array", - "items": { - "$ref": "#/definitions/webhookType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All webhooks to create." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Private DNS zone resource IDs for private endpoint." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." - } - }, - "anonymousPullEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "cacheRules": { - "type": "array", - "items": { - "$ref": "#/definitions/cacheRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cache Rules." - } - }, - "credentialSets": { - "type": "array", - "items": { - "$ref": "#/definitions/credentialSetType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Credential Sets." - } - }, - "scopeMaps": { - "type": "array", - "items": { - "$ref": "#/definitions/scopeMapsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Scope maps setting." - } - }, - "tokens": { - "type": "array", - "items": { - "$ref": "#/definitions/tokenType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tokens to create for the container registry." - } - }, - "tasks": { - "type": "array", - "items": { - "$ref": "#/definitions/taskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of ACR Tasks to create." + "description": "Enable Azure telemetry collection." } } }, "variables": { "copy": [ { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "name": "roleAssignments", + "count": "[length(parameters('acrPullPrincipalIds'))]", + "input": { + "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", + "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", + "principalType": "ServicePrincipal" + } + }, + { + "name": "dnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" + } } ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", - "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", - "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", - "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", - "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", - "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", - "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", - "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", - "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", - "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", - "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" + "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "registry": { - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-06-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('acrSku')]" - }, - "properties": { - "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", - "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", - "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", - "roleAssignmentMode": "[parameters('roleAssignmentMode')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", - "policies": { - "azureADAuthenticationAsArmPolicy": { - "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "acrSku": { + "value": "[parameters('sku')]" + }, + "acrAdminUserEnabled": { + "value": "[parameters('adminUserEnabled')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "exportPolicyStatus": { + "value": "[parameters('exportPolicyStatus')]" }, - "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", - "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", - "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", - "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", - "softDeletePolicy": { - "retentionDays": "[parameters('softDeletePolicyDays')]", - "status": "[parameters('softDeletePolicyStatus')]" + "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[variables('privateEndpointConfig')]" } }, - "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", - "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", - "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", - "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", - "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "registry_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_diagnosticSettings": { - "copy": { - "name": "registry_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1509121545318808417" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR)." }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "credentialSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a credential set." + } + }, + "scopeMapsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" + }, + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a scope map." + } + }, + "cacheRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cache rule." + } + }, + "replicationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" + }, + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replication." + } + }, + "taskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties for the task." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The step properties for the task." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The trigger properties for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the task at the time the operation was called." + }, + "nullable": true + }, + "timeout": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The agent configuration for the task." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." + } + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The log template for the task to use when creating logs in Log Analytics." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a task." + } + }, + "tokenType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map which defines the permissions for this token." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" + }, + "description": "Optional. The status of the token at the time the operation was called." + }, + "nullable": true + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." + } + } + } + }, + "webhookType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the webhook at the time the operation was called." + }, + "nullable": true + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + }, + "description": "Optional. Custom headers that will be added to the webhook notifications." + }, + "nullable": true + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a webhook." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "description": "The type for auth credentials.", + "__bicep_imported_from!": { + "sourceTemplate": "credential-set/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_roleAssignments": { - "copy": { - "name": "registry_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_scopeMaps": { - "copy": { - "name": "registry_scopeMaps", - "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" }, - "actions": { - "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3787322352564227867" + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "autoGeneratedDomainNameLabelScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse", + "Unsecure" + ], + "metadata": { + "description": "Optional. The domain name label reuse scope." + } + }, + "roleAssignmentMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AbacRepositoryPermissions", + "LegacyRegistryPermissions" + ], + "metadata": { + "description": "Optional. The registry permissions role assignment mode." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } }, - "name": "Container Registries scope maps", - "description": "This module deploys an Azure Container Registry (ACR) scope map." - }, - "parameters": { - "registryName": { - "type": "string", + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." } }, - "name": { + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { "type": "string", - "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "Optional. The name of the scope map." + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." } }, - "actions": { + "replications": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/replicationType" }, + "nullable": true, "metadata": { - "description": "Required. The list of scoped permissions for registry artifacts." + "description": "Optional. All replications to create." } }, - "description": { - "type": "string", + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/webhookType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. The user friendly description of the scope map." + "description": "Optional. The managed identity definition for this resource." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "items": { + "$ref": "#/definitions/cacheRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialSetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/scopeMapsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Scope maps setting." + } + }, + "tokens": { + "type": "array", + "items": { + "$ref": "#/definitions/tokenType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tokens to create for the container registry." + } + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/definitions/taskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of ACR Tasks to create." + } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", + "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", + "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", + "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" + }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -25856,5182 +25761,6040 @@ } } }, - "registry": { + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" }, - "scopeMap": { - "type": "Microsoft.ContainerRegistry/registries/scopeMaps", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, "properties": { - "actions": "[parameters('actions')]", - "description": "[parameters('description')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the scope map." + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", + "roleAssignmentMode": "[parameters('roleAssignmentMode')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" }, - "value": "[parameters('name')]" + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the scope map was created in." + "registry_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "registry" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the scope map." + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_replications": { - "copy": { - "name": "registry_replications", - "count": "[length(coalesce(parameters('replications'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" - }, - "regionEndpointEnabled": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" - }, - "zoneRedundancy": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "6219097750044645017" - }, - "name": "Azure Container Registry (ACR) Replications", - "description": "This module deploys an Azure Container Registry (ACR) Replication." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "registry" + ] }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" + ] }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. Tags of the resource." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3787322352564227867" + }, + "name": "Container Registries scope maps", + "description": "This module deploys an Azure Container Registry (ACR) scope map." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } + "dependsOn": [ + "registry" + ] }, - "zoneRedundancy": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6219097750044645017" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13412699468141336519" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set." + }, + "definitions": { + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for auth credentials." + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" } } } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "replication": { - "type": "Microsoft.ContainerRegistry/registries/replications", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", - "zoneRedundancy": "[parameters('zoneRedundancy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the replication." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the replication." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the replication was created in." }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "registry" + ] }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" }, - "value": "[reference('replication', '2025-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_credentialSets": { - "copy": { - "name": "registry_credentialSets", - "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "managedIdentities": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" - }, - "authCredentials": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" - }, - "loginServer": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13412699468141336519" - }, - "name": "Container Registries Credential Sets", - "description": "This module deploys an ACR Credential Set." - }, - "definitions": { - "authCredentialsType": { - "type": "object", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for auth credentials." - } - }, - "managedIdentityOnlySysAssignedType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1319901650921923538" + }, + "name": "Container Registry Cache", + "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "cacheRule": { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "dependsOn": [ + "registry", + "registry_credentialSets" + ] }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" + "registry_tokens": { + "copy": { + "name": "registry_tokens", + "count": "[length(coalesce(parameters('tokens'), createArray()))]" }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "scopeMapResourceId": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5970335582661416899" + }, + "name": "Container Registries Tokens", + "description": "Deploys an Azure Container Registry (ACR) Token." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map to which the token will be associated with." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the token. Default is enabled." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + }, + "description": "Optional. The credentials associated with the token for authentication." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "credentialSet": { - "type": "Microsoft.ContainerRegistry/registries/credentialSets", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", - "properties": { - "authCredentials": "[parameters('authCredentials')]", - "loginServer": "[parameters('loginServer')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Credential Set." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Credential Set." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Credential Set." + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "token": { + "type": "Microsoft.ContainerRegistry/registries/tokens", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "scopeMapId": "[parameters('scopeMapResourceId')]", + "status": "[parameters('status')]", + "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the token." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the token was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the token." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" + } + } + } }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + "dependsOn": [ + "registry", + "registry_scopeMaps" + ] }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." + "registry_tasks": { + "copy": { + "name": "registry_tasks", + "count": "[length(coalesce(parameters('tasks'), createArray()))]" }, - "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_cacheRules": { - "copy": { - "name": "registry_cacheRules", - "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "registryName": { - "value": "[parameters('name')]" - }, - "sourceRepository": { - "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" - }, - "targetRepository": { - "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" - }, - "credentialSetResourceId": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1319901650921923538" - }, - "name": "Container Registry Cache", - "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "defaultValue": "[parameters('sourceRepository')]", - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "platform": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" + }, + "step": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" + }, + "trigger": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" + }, + "timeout": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" + }, + "agentConfiguration": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" + }, + "agentPoolName": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" + }, + "isSystemTask": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" + }, + "logTemplate": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2468771835002458415" + }, + "name": "Container Registries Tasks", + "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." + }, + "definitions": { + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties against which the task has to run." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The properties that describe all triggers for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. The current status of task." + } + }, + "timeout": { + "type": "int", + "defaultValue": 3600, + "minValue": 300, + "maxValue": 28800, + "metadata": { + "description": "Optional. Run timeout in seconds." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The machine configuration of the run agent." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The dedicated agent pool for the task." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" + }, + "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + }, + "nullable": true + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The value of this property indicates whether the task resource is system task or not." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The template that describes the repository and tag information for run log artifact." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "task": { + "type": "Microsoft.ContainerRegistry/registries/tasks", + "apiVersion": "2025-03-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "agentConfiguration": "[parameters('agentConfiguration')]", + "agentPoolName": "[parameters('agentPoolName')]", + "credentials": "[parameters('credentials')]", + "isSystemTask": "[parameters('isSystemTask')]", + "logTemplate": "[parameters('logTemplate')]", + "platform": "[parameters('platform')]", + "status": "[parameters('status')]", + "step": "[parameters('step')]", + "timeout": "[parameters('timeout')]", + "trigger": "[parameters('trigger')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the task." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the task was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the task." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('task', '2025-03-01-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" } } } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "cacheRule": { - "type": "Microsoft.ContainerRegistry/registries/cacheRules", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "sourceRepository": "[parameters('sourceRepository')]", - "targetRepository": "[parameters('targetRepository')]", - "credentialSetResourceId": "[parameters('credentialSetResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Cache Rule." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Cache Rule." }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "registry" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cache Rule." + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry", - "registry_credentialSets" - ] - }, - "registry_tokens": { - "copy": { - "name": "registry_tokens", - "count": "[length(coalesce(parameters('tokens'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "scopeMapResourceId": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" - }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "5970335582661416899" - }, - "name": "Container Registries Tokens", - "description": "Deploys an Azure Container Registry (ACR) Token." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. The name of the token." - } - }, - "scopeMapResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the scope map to which the token will be associated with." - } - }, - "status": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The status of the token. Default is enabled." - } - }, - "credentials": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } }, - "description": "Optional. The credentials associated with the token for authentication." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3200175097987099858" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "securestring", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2025-11-01', 'full').location]" + } + } + } }, - "nullable": true + "dependsOn": [ + "registry" + ] }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "token": { - "type": "Microsoft.ContainerRegistry/registries/tokens", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "scopeMapId": "[parameters('scopeMapResourceId')]", - "status": "[parameters('status')]", - "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the token." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the token was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the token." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry", - "registry_scopeMaps" - ] - }, - "registry_tasks": { - "copy": { - "name": "registry_tasks", - "count": "[length(coalesce(parameters('tasks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "registryName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "platform": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" - }, - "step": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" - }, - "trigger": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" - }, - "timeout": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" - }, - "agentConfiguration": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" - }, - "agentPoolName": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" - }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" - }, - "isSystemTask": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" - }, - "logTemplate": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" - }, - "managedIdentities": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2468771835002458415" - }, - "name": "Container Registries Tasks", - "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." - }, - "definitions": { - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "dependsOn": [ + "registry", + "registry_replications" + ] } }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, + "outputs": { "name": { "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. The name of the task." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" - }, - "description": "Optional. The platform properties against which the task has to run." - }, - "nullable": true - }, - "step": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" - }, - "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + "description": "The Name of the Azure container registry." }, - "nullable": true - }, - "trigger": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" - }, - "description": "Optional. The properties that describe all triggers for the task." - }, - "nullable": true + "value": "[parameters('name')]" }, - "status": { + "loginServer": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], "metadata": { - "description": "Optional. The current status of task." - } + "description": "The reference to the Azure container registry." + }, + "value": "[reference('registry').loginServer]" }, - "timeout": { - "type": "int", - "defaultValue": 3600, - "minValue": 300, - "maxValue": 28800, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "Optional. Run timeout in seconds." - } + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" }, - "agentConfiguration": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" - }, - "description": "Optional. The machine configuration of the run agent." + "description": "The resource ID of the Azure container registry." }, - "nullable": true + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" }, - "agentPoolName": { + "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The dedicated agent pool for the task." - } + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" }, - "credentials": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" - }, - "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + "description": "The location the resource was deployed into." }, - "nullable": true + "value": "[reference('registry', '2025-06-01-preview', 'full').location]" }, - "isSystemTask": { - "type": "bool", - "nullable": true, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", "metadata": { - "description": "Optional. The value of this property indicates whether the task resource is system task or not." + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" } }, - "logTemplate": { - "type": "string", - "nullable": true, + "credentialSetsResourceIds": { + "type": "array", "metadata": { - "description": "Optional. The template that describes the repository and tag information for run log artifact." + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "The private endpoints of the Azure container registry." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "avmContainerRegistryReader", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", + "virtualNetwork" + ] + }, + "avmStorageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "minimumTlsVersion": { + "value": "TLS1_2" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", + "ipRules": [] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "supportsHttpsTrafficOnly": { + "value": true + }, + "accessTier": { + "value": "Hot" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1254456195180100771" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } } } }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoints output." + } + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "task": { - "type": "Microsoft.ContainerRegistry/registries/tasks", - "apiVersion": "2025-03-01-preview", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": { - "agentConfiguration": "[parameters('agentConfiguration')]", - "agentPoolName": "[parameters('agentPoolName')]", - "credentials": "[parameters('credentials')]", - "isSystemTask": "[parameters('isSystemTask')]", - "logTemplate": "[parameters('logTemplate')]", - "platform": "[parameters('platform')]", - "status": "[parameters('status')]", - "step": "[parameters('step')]", - "timeout": "[parameters('timeout')]", - "trigger": "[parameters('trigger')]" } } }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the task." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the task was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the task." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network configuration." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey1 secret name to create." + } + }, + "connectionString1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString1 secret name to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey2 secret name to create." + } + }, + "connectionString2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString2 secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the exported secrets." + } + }, + "localUserType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a local user." + } + }, + "blobServiceType": { + "type": "object", + "properties": { + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/blobCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "versionDeletePolicyDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a blob service." + } + }, + "fileServiceType": { + "type": "object", + "properties": { + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('task', '2025-03-01-preview', 'full').location]" + "description": "Optional. Protocol settings for file service." + }, + "nullable": true + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" - } + "description": "Optional. The service properties for soft delete." + }, + "nullable": true + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/fileCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "dependsOn": [ - "registry" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type of a file service." + } }, - "registry_webhooks": { - "copy": { - "name": "registry_webhooks", - "count": "[length(coalesce(parameters('webhooks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "queueServiceType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "action": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" }, - "customHeaders": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/queueCorsRuleType" }, - "scope": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" }, - "status": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a queue service." + } + }, + "tableServiceType": { + "type": "object", + "properties": { + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" }, - "serviceUri": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/tableCorsRuleType" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a table service." + } + }, + "objectReplicationPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "destinationStorageAccountResourceId": { + "type": "string", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3200175097987099858" - }, - "name": "Azure Container Registry (ACR) Webhooks", - "description": "This module deploys an Azure Container Registry (ACR) Webhook." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}webhook', parameters('registryName'))]", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "securestring", - "metadata": { - "description": "Required. The service URI for the webhook to post notifications." - } - }, - "status": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The status of the webhook at the time the operation was called." - } - }, - "action": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [ - "chart_delete", - "chart_push", - "delete", - "push", - "quarantine" - ], - "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "customHeaders": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Custom headers that will be added to the webhook notifications." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "webhook": { - "type": "Microsoft.ContainerRegistry/registries/webhooks", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "actions": "[parameters('action')]", - "customHeaders": "[parameters('customHeaders')]", - "scope": "[parameters('scope')]", - "serviceUri": "[parameters('serviceUri')]", - "status": "[parameters('status')]" - } - } + "description": "Required. The resource ID of the destination storage account." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the webhook." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the webhook." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Azure container registry." - }, - "value": "[resourceGroup().name]" - }, - "actions": { - "type": "array", - "metadata": { - "description": "The actions of the webhook." - }, - "value": "[reference('webhook').actions]" - }, - "status": { - "type": "string", - "metadata": { - "description": "The status of the webhook." - }, - "value": "[reference('webhook').status]" - }, - "provistioningState": { - "type": "string", - "metadata": { - "description": "The provisioning state of the webhook." - }, - "value": "[reference('webhook').provisioningState]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('webhook', '2025-11-01', 'full').location]" - } + "metadata": { + "description": "Required. The storage account object replication rules." } } }, - "dependsOn": [ - "registry" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy." + } }, - "registry_privateEndpoints": { - "copy": { - "name": "registry_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "_1.immutabilityPolicyType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/container/main.bicep" + } + } + }, + "_2.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { + "memberName": { "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." } }, - "location": { + "privateIPAddress": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "blobCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/_1.immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type of a storage container.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." } }, - "dependsOn": [ - "privateEndpoint" - ] + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } } }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "fileCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a file share.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { "type": "array", "items": { "type": "string" }, + "nullable": true, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "description": "Optional. The prefix to match for the replication policy rule." + } }, - "groupId": { + "minCreationTime": { "type": "string", "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "description": "Optional. The minimum creation time to match for the replication policy rule." + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "object-replication-policy/policy/main.bicep" + } + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "queueCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a queue.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_2.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "tableCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." } } }, - "dependsOn": [ - "registry", - "registry_replications" - ] + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a table.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep" + } + } } }, - "outputs": { + "parameters": { "name": { "type": "string", + "maxLength": 24, "metadata": { - "description": "The Name of the Azure container registry." - }, - "value": "[parameters('name')]" + "description": "Required. Name of the Storage Account. Must be lower-case." + } }, - "loginServer": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "The reference to the Azure container registry." - }, - "value": "[reference('registry').loginServer]" + "description": "Optional. Location for all resources." + } }, - "resourceGroupName": { + "extendedLocationZone": { "type": "string", + "nullable": true, "metadata": { - "description": "The name of the Azure container registry." + "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "value": "[resourceGroup().name]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } }, - "resourceId": { + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], "metadata": { - "description": "The resource ID of the Azure container registry." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + "description": "Optional. Type of Storage Account to create." + } }, - "systemAssignedMIPrincipalId": { + "skuName": { "type": "string", - "nullable": true, + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS", + "Standard_GRS", + "Standard_GZRS", + "Standard_RAGRS", + "Standard_RAGZRS", + "StandardV2_LRS", + "StandardV2_ZRS", + "StandardV2_GRS", + "StandardV2_GZRS", + "Premium_LRS", + "Premium_ZRS", + "PremiumV2_LRS", + "PremiumV2_ZRS" + ], "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" + "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." + } }, - "location": { + "accessTier": { "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "Cold" + ], "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('registry', '2025-06-01-preview', 'full').location]" + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } }, - "credentialSetsSystemAssignedMIPrincipalIds": { - "type": "array", + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" + "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." } }, - "credentialSetsResourceIds": { - "type": "array", + "azureFilesIdentityBasedAuthentication": { + "type": "object", "metadata": { - "description": "The Resource IDs of the ACR Credential Sets." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" + }, + "description": "Optional. Provides the identity based authentication settings for Azure Files." }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" + "nullable": true + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." } }, "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "$ref": "#/definitions/privateEndpointMultiServiceType" }, + "nullable": true, "metadata": { - "description": "The private endpoints of the Azure container registry." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "value": "[reference('avmContainerRegistry').outputs.name.value]" - }, - "resourceId": { - "type": "string", - "value": "[reference('avmContainerRegistry').outputs.resourceId.value]" - }, - "loginServer": { - "type": "string", - "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" - } - } - } - }, - "dependsOn": [ - "avmContainerRegistryReader", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", - "virtualNetwork" - ] - }, - "avmStorageAccount": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "minimumTlsVersion": { - "value": "TLS1_2" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", - "ipRules": [] - } - }, - "requireInfrastructureEncryption": { - "value": true - }, - "supportsHttpsTrafficOnly": { - "value": true - }, - "accessTier": { - "value": "Hot" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1254456195180100771" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + }, + "managementPolicyRules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoints output." - } - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } + "description": "Optional. The Storage Account ManagementPolicies Rules." }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network configuration." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey1 secret name to create." - } - }, - "connectionString1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString1 secret name to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey2 secret name to create." - } - }, - "connectionString2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString2 secret name to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the exported secrets." - } - }, - "localUserType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The local user home directory." - } - }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" - }, - "metadata": { - "description": "Required. The permission scopes of the local user." - } - }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a local user." - } - }, - "blobServiceType": { - "type": "object", - "properties": { - "automaticSnapshotPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." - } - }, - "changeFeedEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." - } - }, - "changeFeedRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 146000, - "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." - } - }, - "containerDeleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." - } - }, - "containerDeleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." - } - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/blobCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "defaultServiceVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." - } - }, - "deleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob soft delete." - } - }, - "deleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." - } - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "isVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." - } - }, - "versionDeletePolicyDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." - } - }, - "lastAccessTimeTrackingPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." - } - }, - "restorePolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." - } - }, - "restorePolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Blob containers to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a blob service." - } - }, - "fileServiceType": { - "type": "object", - "properties": { - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" - }, - "description": "Optional. Protocol settings for file service." - }, - "nullable": true - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" - }, - "description": "Optional. The service properties for soft delete." - }, - "nullable": true - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/fileCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a file service." - } - }, - "queueServiceType": { - "type": "object", - "properties": { - "queues": { - "type": "array", - "items": { - "$ref": "#/definitions/queueType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Queues to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/queueCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a queue service." - } - }, - "tableServiceType": { - "type": "object", - "properties": { - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/tableCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a table service." - } - }, - "objectReplicationPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." - } - }, - "destinationStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the destination storage account." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. The storage account object replication rules." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy." - } - }, - "_1.immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - } - }, - "metadata": { - "description": "The type for an immutability policy.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/container/main.bicep" - } - } - }, - "_2.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "nullable": true + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." } }, - "memberName": { + "dnsEndpointType": { "type": "string", + "nullable": true, + "allowedValues": [ + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "$ref": "#/definitions/blobServiceType", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "$ref": "#/definitions/fileServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "$ref": "#/definitions/queueServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "$ref": "#/definitions/tableServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." } }, - "privateIPAddress": { + "minimumTlsVersion": { "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_2", + "TLS1_3" + ], "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "blobCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "containerType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } - }, - "immutabilityPolicy": { - "$ref": "#/definitions/_1.immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" }, - "description": "Optional. A name-value pair to associate with the container as metadata." - }, - "nullable": true - }, - "publicAccess": { - "type": "string", - "allowedValues": [ - "Blob", - "Container", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type of a storage container.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + }, + "localUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/localUserType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "fileCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." - } - }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, - "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a file share.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, "nullable": true, "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "minCreationTime": { + "allowedCopyScope": { "type": "string", "nullable": true, + "allowedValues": [ + "AAD", + "PrivateLink" + ], "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "description": "The type of an object replication policy rule.", - "__bicep_imported_from!": { - "sourceTemplate": "object-replication-policy/policy/main.bicep" - } - } - }, - "permissionScopeType": { - "type": "object", - "properties": { - "permissions": { - "type": "string", - "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." - } - }, - "resourceName": { - "type": "string", - "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "queueCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "queueType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the queue." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a queue.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_2.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "sshAuthorizedKeyType": { - "type": "object", - "properties": { - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description used to store the function/usage of the key." - } - }, - "key": { - "type": "securestring", - "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } - } - }, - "tableCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a table.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "extendedLocationZone": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "kind": { - "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_ZRS", - "Standard_GRS", - "Standard_GZRS", - "Standard_RAGRS", - "Standard_RAGZRS", - "StandardV2_LRS", - "StandardV2_ZRS", - "StandardV2_GRS", - "StandardV2_GZRS", - "Premium_LRS", - "Premium_ZRS", - "PremiumV2_LRS", - "PremiumV2_ZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "Cold" - ], - "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." - } - }, - "largeFileSharesState": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" - }, - "description": "Optional. Provides the identity based authentication settings for Azure Files." - }, - "nullable": true - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } - }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "managementPolicyRules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Optional. The Storage Account ManagementPolicies Rules." - }, - "nullable": true - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, - "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." - } - }, - "customDomainName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." - } - }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." - } - }, - "dnsEndpointType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "$ref": "#/definitions/blobServiceType", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "$ref": "#/definitions/fileServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "$ref": "#/definitions/queueServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "$ref": "#/definitions/tableServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. Table service and tables to create." - } - }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_2", - "TLS1_3" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." - } - }, - "enableSftp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "localUsers": { - "type": "array", - "items": { - "$ref": "#/definitions/localUserType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Local users to deploy for SFTP authentication." - } - }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables local users feature, if set to true." - } - }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "allowedCopyScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AAD", - "PrivateLink" - ], - "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "sasExpirationAction": { - "type": "string", - "defaultValue": "Log", - "allowedValues": [ - "Block", - "Log" - ], - "metadata": { - "description": "Optional. The SAS expiration action. Allowed values are Block and Log." - } - }, - "keyType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], - "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "immutableStorageWithVersioning": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" - }, - "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." - }, - "nullable": true - }, - "objectReplicationPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Object replication policies for the storage account." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", - "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2025-05-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "sasExpirationAction": { + "type": "string", + "defaultValue": "Log", + "allowedValues": [ + "Block", + "Log" + ], + "metadata": { + "description": "Optional. The SAS expiration action. Allowed values are Block and Log." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "immutableStorageWithVersioning": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" + }, + "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." + }, + "nullable": true + }, + "objectReplicationPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Object replication policies for the storage account." + } } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_roleAssignments": { - "copy": { - "name": "storageAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2025-05-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } }, - "nullable": true + "dependsOn": [ + "storageAccount" + ] }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[variables('formattedManagementPolicies')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4000605059554016072" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Required. The Storage Account ManagementPolicies Rules." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" } } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "storageAccount", + "storageAccount_blobServices" ] }, - "privateEndpoint_roleAssignments": { + "storageAccount_localUsers": { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "name": "storageAccount_localUsers", + "count": "[length(coalesce(parameters('localUsers'), createArray()))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1801226901235196767" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } }, "dependsOn": [ - "privateEndpoint" + "storageAccount" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "storageAccountName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" } }, "template": { @@ -31041,1235 +31804,2222 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "version": "0.41.2.15936", + "templateHash": "468225492069709453" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." }, "definitions": { - "privateDnsZoneGroupConfigType": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a storage container." + } + }, + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "privateDnsZoneResourceId": { + "workspaceResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "container/main.bicep" + } } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "roleAssignmentType": { + "type": "object", "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_managementPolicies": { - "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "rules": { - "value": "[variables('formattedManagementPolicies')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4000605059554016072" - }, - "name": "Storage Account Management Policies", - "description": "This module deploys a Storage Account Management Policy." - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Required. The Storage Account ManagementPolicies Rules." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - { - "type": "Microsoft.Storage/storageAccounts/managementPolicies", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", - "properties": { - "policy": { - "rules": "[parameters('rules')]" - } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed management policy." - }, - "value": "default" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed management policy." - }, - "value": "default" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed management policy." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] - }, - "storageAccount_localUsers": { - "copy": { - "name": "storageAccount_localUsers", - "count": "[length(coalesce(parameters('localUsers'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" - }, - "hasSshKey": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" - }, - "hasSshPassword": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" - }, - "permissionScopes": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" - }, - "hasSharedKey": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" - }, - "homeDirectory": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" - }, - "sshAuthorizedKeys": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1801226901235196767" - }, - "name": "Storage Account Local Users", - "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." - }, - "definitions": { - "sshAuthorizedKeyType": { - "type": "object", - "properties": { - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description used to store the function/usage of the key." - } - }, - "key": { - "type": "securestring", - "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "permissionScopeType": { - "type": "object", - "properties": { - "permissions": { - "type": "string", - "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." - } - }, - "resourceName": { - "type": "string", - "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The local user home directory." - } - }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" - }, - "metadata": { - "description": "Required. The permission scopes of the local user." - } - }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } } - } - } - } - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "localUsers": { - "type": "Microsoft.Storage/storageAccounts/localUsers", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "hasSharedKey": "[parameters('hasSharedKey')]", - "hasSshKey": "[parameters('hasSshKey')]", - "hasSshPassword": "[parameters('hasSshPassword')]", - "homeDirectory": "[parameters('homeDirectory')]", - "permissionScopes": "[parameters('permissionScopes')]", - "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed local user." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed local user." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed local user." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_blobServices": { - "condition": "[not(empty(parameters('blobServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "containers": { - "value": "[tryGet(parameters('blobServices'), 'containers')]" - }, - "automaticSnapshotPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" - }, - "changeFeedEnabled": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" - }, - "changeFeedRetentionInDays": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" - }, - "containerDeleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" - }, - "containerDeleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" - }, - "corsRules": { - "value": "[tryGet(parameters('blobServices'), 'corsRules')]" - }, - "defaultServiceVersion": { - "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" - }, - "deleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" - }, - "deleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" - }, - "isVersioningEnabled": { - "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" - }, - "lastAccessTimeTrackingPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" - }, - "restorePolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" - }, - "restorePolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "468225492069709453" - }, - "name": "Storage Account blob Services", - "description": "This module deploys a Storage Account Blob Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" + "variables": { + "enableReferencedModulesTelemetry": false, + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[parameters('defaultServiceVersion')]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "273904034769611992" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an immutability policy." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "defaultValue": {} + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "container_immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15304742179563677019" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "blobServices" + ] + } }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } + "dependsOn": [ + "storageAccount" + ] }, - "containerType": { - "type": "object", + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + }, + "corsRules": { + "value": "[tryGet(parameters('fileServices'), 'corsRules')]" } }, - "metadata": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17583198711200998285" }, - "description": "Optional. A name-value pair to associate with the container as metadata." - }, - "nullable": true - }, - "publicAccess": { - "type": "string", - "allowedValues": [ - "Blob", - "Container", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a storage container." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a file share." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "defaultValue": {} + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "defaultValue": { + "enabled": true, + "days": 7 + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - } - }, - "metadata": { - "description": "The type for an immutability policy.", - "__bicep_imported_from!": { - "sourceTemplate": "container/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "automaticSnapshotPolicyEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." - } - }, - "changeFeedEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." - } - }, - "changeFeedRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 146000, - "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." - } - }, - "containerDeleteRetentionPolicyEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." - } - }, - "containerDeleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." - } - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "defaultServiceVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." - } - }, - "deleteRetentionPolicyEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. The blob service properties for blob soft delete." - } - }, - "deleteRetentionPolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." - } - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "isVersioningEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." - } - }, - "lastAccessTimeTrackingPolicyEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." - } - }, - "restorePolicyEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." - } - }, - "restorePolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, - "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Blob containers to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false, - "name": "default" - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "blobServices": { - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", - "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", - "containerDeleteRetentionPolicy": { - "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", - "days": "[parameters('containerDeleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" - }, - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "defaultServiceVersion": "[parameters('defaultServiceVersion')]", - "deleteRetentionPolicy": { - "enabled": "[parameters('deleteRetentionPolicyEnabled')]", - "days": "[parameters('deleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" - }, - "isVersioningEnabled": "[parameters('isVersioningEnabled')]", - "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", - "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "blobServices_diagnosticSettings": { - "copy": { - "name": "blobServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "provisionedBandwidthMibps": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + }, + "provisionedIops": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10353179772982843397" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]", + "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", + "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "blobServices" + "storageAccount" ] }, - "blobServices_container": { - "copy": { - "name": "blobServices_container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" - }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -32277,43 +34027,16 @@ "mode": "Incremental", "parameters": { "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "blobServiceName": { - "value": "[variables('name')]" - }, - "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" - }, - "defaultEncryptionScope": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" - }, - "denyEncryptionScopeOverride": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" - }, - "enableNfsV3AllSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" - }, - "enableNfsV3RootSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" - }, - "immutableStorageWithVersioningEnabled": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" - }, - "publicAccess": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + "value": "[parameters('name')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" }, - "immutabilityPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" } }, "template": { @@ -32324,40 +34047,227 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "273904034769611992" + "templateHash": "9644461291744477521" }, - "name": "Storage Account Blob Containers", - "description": "This module deploys a Storage Account Blob Container." + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." }, "definitions": { - "immutabilityPolicyType": { + "corsRuleType": { "type": "object", "properties": { - "immutabilityPeriodSinceCreationInDays": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a queue." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." } }, - "allowProtectedAppendWrites": { - "type": "bool", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "allowProtectedAppendWritesAll": { - "type": "bool", + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for an immutability policy." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, "roleAssignmentType": { @@ -32444,200 +34354,105 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "blobServiceName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } - }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. A name-value pair to associate with the container as metadata." + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" }, - "defaultValue": {} - }, - "publicAccess": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Container", - "Blob", - "None" - ], + "defaultValue": [], "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + "description": "Optional. Queues to create." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." } }, - "roleAssignments": { + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/diagnosticSettingFullType" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The diagnostic settings of the service." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount::blobServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, - "container": { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", "properties": { - "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", - "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", - "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", - "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", - "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", - "metadata": "[parameters('metadata')]", - "publicAccess": "[parameters('publicAccess')]" + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" } }, - "container_roleAssignments": { + "queueServices_diagnosticSettings": { "copy": { - "name": "container_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "container" + "queueServices" ] }, - "container_immutabilityPolicy": { - "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -32647,17 +34462,14 @@ "storageAccountName": { "value": "[parameters('storageAccountName')]" }, - "containerName": { - "value": "[parameters('name')]" - }, - "immutabilityPeriodSinceCreationInDays": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" }, - "allowProtectedAppendWrites": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" }, - "allowProtectedAppendWritesAll": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -32665,15 +34477,93 @@ }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "15304742179563677019" + "templateHash": "12812824360066955039" }, - "name": "Storage Account Blob Container Immutability Policies", - "description": "This module deploys a Storage Account Blob Container Immutability Policy." + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { "storageAccountName": { @@ -32683,31 +34573,30 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "containerName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." - } - }, - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "defaultValue": 365, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + "description": "Required. The name of the storage queue to deploy." } }, - "allowProtectedAppendWrites": { - "type": "bool", - "defaultValue": false, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair that represents queue metadata." + }, + "defaultValue": {} }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "defaultValue": false, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + "description": "Optional. Array of role assignments to create." } }, "enableTelemetry": { @@ -32718,12 +34607,42 @@ } } }, - "resources": [ - { + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -32739,66 +34658,89 @@ } } }, - { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", "properties": { - "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", - "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", - "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + "metadata": "[parameters('metadata')]" } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] } - ], + }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed immutability policy." + "description": "The name of the deployed queue." }, - "value": "default" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed immutability policy." + "description": "The resource ID of the deployed queue." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed immutability policy." + "description": "The resource group of the deployed queue." }, "value": "[resourceGroup().name]" } } } - }, - "dependsOn": [ - "container" - ] + } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed container." + "description": "The name of the deployed queue service." }, - "value": "[parameters('name')]" + "value": "[variables('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed container." + "description": "The resource ID of the deployed queue service." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed container." + "description": "The resource group of the deployed queue service." }, "value": "[resourceGroup().name]" } @@ -32806,601 +34748,735 @@ } }, "dependsOn": [ - "blobServices" + "storageAccount" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed blob service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - }, - "corsRules": { - "value": "[tryGet(parameters('fileServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17583198711200998285" }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + }, + "corsRules": { + "value": "[tryGet(parameters('tableServices'), 'corsRules')]" } }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10320403358700650147" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a file share." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" - }, - "description": "Optional. Protocol settings for file service." - }, - "defaultValue": {} - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" - }, - "description": "Optional. The service properties for soft delete." - }, - "defaultValue": { - "enabled": true, - "days": 7 - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } - }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11362260974696477885" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "fileServices" + "storageAccount" ] }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" - }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" - }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" - }, - "provisionedBandwidthMibps": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" - }, - "provisionedIops": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" } }, "template": { @@ -33411,711 +35487,1739 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "10353179772982843397" - }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share." + "templateHash": "13227497656004178962" + } }, "definitions": { - "roleAssignmentType": { + "secretSetOutputType": { "type": "object", "properties": { - "name": { + "secretResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "The resourceId of the exported secret." } }, - "roleDefinitionIdOrName": { + "secretUri": { "type": "string", "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "The secret URI of the exported secret." } }, - "principalId": { + "secretUriWithVersion": { "type": "string", "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "The secret URI with version of the exported secret." } - }, - "principalType": { + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Required. The name of the secret to set." } }, - "description": { + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_objectReplicationPolicies": { + "copy": { + "name": "storageAccount_objectReplicationPolicies", + "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "destinationAccountResourceId": { + "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" + }, + "enableMetrics": { + "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" + }, + "rules": { + "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1894366578172550759" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." } }, - "condition": { + "containerName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Required. The name of the source container." } }, - "conditionVersion": { + "destinationContainerName": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The filters for the object replication policy rule." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "The type of an object replication policy rule.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "policy/main.bicep" } } } }, "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { "type": "string", "nullable": true, - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], - "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." - } - }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + "description": "Optional. Name of the policy." } }, - "enabledProtocols": { + "storageAccountName": { "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "maxLength": 24, "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Required. The name of the parent Storage Account." } }, - "rootSquash": { + "destinationAccountResourceId": { "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "minValue": 0, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." - } - }, - "provisionedIops": { - "type": "int", - "nullable": true, - "minValue": 0, - "maxValue": 102400, "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + "description": "Required. Resource ID of the destination storage account for replication." } }, - "enableTelemetry": { + "enableMetrics": { "type": "bool", - "defaultValue": true, + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Whether metrics are enabled for the object replication policy." } }, - "roleAssignments": { + "rules": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/objectReplicationPolicyRuleType" }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Required. Rules for the object replication policy." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", + "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", + "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", + "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" }, "resources": { - "storageAccount::fileService": { + "storageAccount": { "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", + "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + "name": "[parameters('storageAccountName')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "destinationPolicy": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", + "subscriptionId": "[variables('destAccountSubscription')]", + "resourceGroup": "[variables('destAccountResourceGroupName')]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('name'), 'default')]" + }, + "storageAccountName": { + "value": "[variables('destAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "value": "[parameters('rules')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" } } } } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]", - "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", - "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "fileShare_roleAssignments": { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, + "sourcePolicy": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "scope": { - "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" - }, "name": { - "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + "value": "[reference('destinationPolicy').outputs.policyId.value]" }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + "storageAccountName": { + "value": "[parameters('storageAccountName')]" }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" }, - "condition": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" }, - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "enableMetrics": { + "value": "[parameters('enableMetrics')]" }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + "rules": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('rules'))]", + "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } + ] } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, "parameters": { - "scope": { + "name": { "type": "string", "metadata": { - "description": "Required. The scope to deploy the role assignment to." + "description": "Required. Name of the policy." } }, - "name": { + "storageAccountName": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Required. The name of the role assignment." + "description": "Required. The name of the Storage Account on which to create the policy." } }, - "roleDefinitionId": { + "sourceStorageAccountResourceId": { "type": "string", "metadata": { - "description": "Required. The role definition Id to assign." + "description": "Required. Resource ID of the source storage account for replication." } }, - "principalId": { + "destinationAccountResourceId": { "type": "string", "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Required. Resource ID of the destination storage account for replication." } }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", + "enableMetrics": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Whether metrics are enabled for the object replication policy." } }, - "description": { - "type": "string", - "defaultValue": "", + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Required. Rules for the object replication policy." } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" }, - "condition": { + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" - } + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" }, - "conditionVersion": { + "objectReplicationPolicyId": { "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", "metadata": { - "description": "Optional. Version of the condition." - } + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" }, - "delegatedManagedIdentityResourceId": { + "policyId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[parameters('scope')]", - "name": "[parameters('name')]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "principalId": "[parameters('principalId')]", - "description": "[parameters('description')]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" } - ] + } } }, "dependsOn": [ - "fileShare" + "destinationPolicy" ] } }, - "outputs": { - "name": { + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.policyId.value]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2025-06-01', 'full').location]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." + }, + "value": "[reference('storageAccount').primaryEndpoints]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Storage Account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The primary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + }, + "secondaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The secondary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" + }, + "primaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" + }, + "secondaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", + "virtualNetwork" + ] + }, + "avmAiServices": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "projectName": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "projectDescription": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "existingFoundryProjectResourceId": { + "value": "[variables('existingProjectResourceId')]" + }, + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "sku": { + "value": "S0" + }, + "allowProjectManagement": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "kind": { + "value": "AIServices" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('azureAiServiceLocation')]" + } + }, + "customSubDomainName": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", + "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" + } + }, + "disableLocalAuth": { + "value": true + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "deployments": { + "value": [ + { + "name": "[parameters('gptModelName')]", + "model": { + "format": "OpenAI", + "name": "[parameters('gptModelName')]", + "version": "[parameters('gptModelVersion')]" + }, + "sku": { + "name": "[parameters('deploymentType')]", + "capacity": "[parameters('gptDeploymentCapacity')]" + }, + "raiPolicyName": "Microsoft.Default" + } + ] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18336251851332975005" + }, + "name": "Cognitive Services", + "description": "This module deploys a Cognitive Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "The name of the deployed file share." - }, - "value": "[parameters('name')]" + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceId": { + "memberName": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceGroupName": { + "privateIPAddress": { "type": "string", "metadata": { - "description": "The resource group of the deployed file share." - }, - "value": "[resourceGroup().name]" + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." } } }, - "dependsOn": [ - "fileServices", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", "metadata": { - "description": "The name of the deployed file share service." - }, - "value": "[parameters('name')]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "resourceId": { - "type": "string", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, "metadata": { - "description": "The resource ID of the deployed file share service." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "resourceGroupName": { - "type": "string", + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, "metadata": { - "description": "The resource group of the deployed file share service." + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/project.bicep" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_queueServices": { - "condition": "[not(empty(parameters('queueServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" - }, - "queues": { - "value": "[tryGet(parameters('queueServices'), 'queues')]" - }, - "corsRules": { - "value": "[tryGet(parameters('queueServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9644461291744477521" + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "name": "Storage Account Queue Services", - "description": "This module deploys a Storage Account Queue Service." - }, - "definitions": { - "corsRuleType": { + "diagnosticSettingFullType": { "type": "object", "properties": { - "allowedHeaders": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } }, + "nullable": true, "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "allowedMethods": { + "metricCategories": { "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" + "AzureDiagnostics", + "Dedicated" ], + "nullable": true, "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, + "workspaceResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "maxAgeInSeconds": { - "type": "int", + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "queueType": { + "lockType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the queue." + "description": "Optional. Specify the name of lock." } }, - "metadata": { - "type": "object", + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true + "description": "Optional. Specify the type of lock." + } }, - "roleAssignments": { + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a queue." + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "diagnosticSettingFullType": { + "privateEndpointSingleServiceType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "logCategoriesAndGroups": { + "customDnsConfigs": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" }, "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Optional. Custom DNS configurations." } }, - "metricCategories": { + "ipConfigurations": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" }, "nullable": true, "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." } }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." } }, - "workspaceResourceId": { + "customNetworkInterfaceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." } }, - "storageAccountResourceId": { - "type": "string", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Specify the type of lock." } }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. Array of role assignments to create." } }, - "eventHubName": { - "type": "string", + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." } }, - "marketplacePartnerResourceId": { - "type": "string", + "enableTelemetry": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, @@ -34190,138 +37294,428 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "storageAccountName": { + "name": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Required. The name of Cognitive Services account." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "" + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." } }, - "queues": { + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/queueType" + "$ref": "#/definitions/diagnosticSettingFullType" }, - "defaultValue": [], + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Queues to create." + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." } }, - "corsRules": { + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/corsRuleType" + "$ref": "#/definitions/privateEndpointSingleServiceType" }, "nullable": true, "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, - "diagnosticSettings": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "allowProjectManagement": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable project management feature for AI Foundry." } } }, "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", + "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" }, "resources": { - "storageAccount": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" }, - "queueServices": { - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "queueServices_diagnosticSettings": { - "copy": { - "name": "queueServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2025-01-31-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "cognitiveServiceNew": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "allowProjectManagement": "[parameters('allowProjectManagement')]", + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" }, "dependsOn": [ - "queueServices" + "cMKKeyVault", + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" ] }, - "queueServices_queues": { - "copy": { - "name": "queueServices_queues", - "count": "[length(coalesce(parameters('queues'), createArray()))]" - }, + "cognitiveServiceExisting": { + "condition": "[variables('useExistingService')]", + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "cognitive_service_dependencies": { + "condition": "[not(variables('useExistingService'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" }, "name": { - "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + "value": "[parameters('name')]" }, - "metadata": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[parameters('roleAssignments')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -34331,736 +37725,697 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "12812824360066955039" - }, - "name": "Storage Account Queues", - "description": "This module deploys a Storage Account Queue." + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } }, "definitions": { - "roleAssignmentType": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." } }, - "roleDefinitionIdOrName": { + "raiPolicyName": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of RAI policy." } }, - "principalId": { + "versionUpgradeOption": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The version upgrade option." } - }, - "principalType": { + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Type of the endpoint." } }, - "description": { + "endpoint": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "The endpoint URI." } - }, - "condition": { + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." } }, - "conditionVersion": { + "accessKey1Name": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The name for the accessKey1 secret to create." } }, - "delegatedManagedIdentityResourceId": { + "accessKey2Name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The name for the accessKey2 secret to create." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the storage queue to deploy." + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." } }, - "metadata": { + "_1.privateEndpointCustomDnsConfigType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } }, - "description": "Optional. A name-value pair that represents queue metadata." - }, - "defaultValue": {} - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "storageAccount::queueServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "queue": { - "type": "Microsoft.Storage/storageAccounts/queueServices/queues", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "_1.secretSetOutputType": { + "type": "object", "properties": { - "metadata": "[parameters('metadata')]" + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "queue_roleAssignments": { - "copy": { - "name": "queue_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "aiProjectOutputType": { + "type": "object", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "queue" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed queue." + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed queue." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed queue." - }, - "value": "[resourceGroup().name]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed queue service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed queue service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed queue service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_tableServices": { - "condition": "[not(empty(parameters('tableServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" - }, - "tables": { - "value": "[tryGet(parameters('tableServices'), 'tables')]" - }, - "corsRules": { - "value": "[tryGet(parameters('tableServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "10320403358700650147" - }, - "name": "Storage Account Table Services", - "description": "This module deploys a Storage Account Table Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "tableServices": { - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" - } - }, - "tableServices_diagnosticSettings": { - "copy": { - "name": "tableServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "tableServices" - ] - }, - "tableServices_tables": { - "copy": { - "name": "tableServices_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "11362260974696477885" }, - "name": "Storage Account Table", - "description": "This module deploys a Storage Account Table." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -35130,19 +38485,108 @@ } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, "roleAssignments": { @@ -35155,17 +38599,33 @@ "description": "Optional. Array of role assignments to create." } }, - "name": { + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { "type": "string", "metadata": { - "description": "Required. Name of the table." + "description": "Optional: Name for the project which needs to be created." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "projectDescription": { + "type": "string", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" } } }, @@ -35178,66 +38638,121 @@ } ], "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "enableReferencedModulesTelemetry": false }, "resources": { - "storageAccount::tableServices": { + "cognitiveService": { "existing": true, - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } - } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "table": { - "type": "Microsoft.Storage/storageAccounts/tableServices/tables", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" - }, - "table_roleAssignments": { + "cognitiveService_roleAssignments": { "copy": { - "name": "table_roleAssignments", + "name": "cognitiveService_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -35246,3022 +38761,3366 @@ "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "table" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed table." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed table." - }, - "value": "[resourceGroup().name]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed table service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed table service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed table service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13227497656004178962" - } - }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_objectReplicationPolicies": { - "copy": { - "name": "storageAccount_objectReplicationPolicies", - "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "destinationAccountResourceId": { - "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" - }, - "enableMetrics": { - "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" - }, - "rules": { - "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1894366578172550759" - }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } - }, - "minCreationTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "description": "The type of an object replication policy rule.", - "__bicep_imported_from!": { - "sourceTemplate": "policy/main.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the parent Storage Account." - } - }, - "destinationAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." - } - } - }, - "variables": { - "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", - "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", - "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", - "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "destinationPolicy": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", - "subscriptionId": "[variables('destAccountSubscription')]", - "resourceGroup": "[variables('destAccountResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('name'), 'default')]" - }, - "storageAccountName": { - "value": "[variables('destAccountName')]" - }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" - }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" - }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" - }, - "rules": { - "value": "[parameters('rules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14995722372031126283" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, - "destinationContainerName": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { "type": "array", "items": { "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "minCreationTime": { + "customNetworkInterfaceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy rule." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." - } - }, - "sourceStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the source storage account for replication." - } - }, - "destinationAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" - }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').policyId]" - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true - }, - "description": "Rules created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').rules]" - } - } - } - } - }, - "sourcePolicy": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[reference('destinationPolicy').outputs.policyId.value]" - }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" - }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" - }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" - }, - "rules": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('rules'))]", - "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14995722372031126283" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" } }, - "destinationContainerName": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/secretToSetType" }, - "nullable": true, "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." + "description": "Required. The secrets to set in the Key Vault." } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" }, - "minCreationTime": { - "type": "string", - "nullable": true, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } } } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." } } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy rule." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." - } - }, - "sourceStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the source storage account for replication." - } - }, - "destinationAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" - } - } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" + "expressionEvaluationOptions": { + "scope": "inner" }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').policyId]" - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } }, - "description": "Rules created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').rules]" - } - } - } - }, - "dependsOn": [ - "destinationPolicy" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.policyId.value]" - } - } - } - }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2025-06-01', 'full').location]" - }, - "serviceEndpoints": { - "type": "object", - "metadata": { - "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." - }, - "value": "[reference('storageAccount').primaryEndpoints]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the Storage Account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "primaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The primary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - }, - "secondaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The secondary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" - }, - "primaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" - }, - "secondaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", - "virtualNetwork" - ] - }, - "avmAiServices": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "projectName": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "projectDescription": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "existingFoundryProjectResourceId": { - "value": "[variables('existingProjectResourceId')]" - }, - "location": { - "value": "[parameters('azureAiServiceLocation')]" - }, - "sku": { - "value": "S0" - }, - "allowProjectManagement": { - "value": true - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "kind": { - "value": "AIServices" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('azureAiServiceLocation')]" - } - }, - "customSubDomainName": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" - } - }, - "disableLocalAuth": { - "value": true - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "deployments": { - "value": [ - { - "name": "[parameters('gptModelName')]", - "model": { - "format": "OpenAI", - "name": "[parameters('gptModelName')]", - "version": "[parameters('gptModelVersion')]" - }, - "sku": { - "name": "[parameters('deploymentType')]", - "capacity": "[parameters('gptDeploymentCapacity')]" - }, - "raiPolicyName": "Microsoft.Default" - } - ] - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "9621562991003135575" - }, - "name": "Cognitive Services", - "description": "This module deploys a Cognitive Service." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/project.bicep" - } - } - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } + }, + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "dependsOn": [ + "cognitiveServiceNew" + ] }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "projectName": { - "type": "string", - "metadata": { - "description": "Optional: Name for the project which needs to be created." - } - }, - "projectDescription": { - "type": "string", - "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "" - }, - "kind": { - "type": "string", - "allowedValues": [ - "AIServices", - "AnomalyDetector", - "CognitiveServices", - "ComputerVision", - "ContentModerator", - "ContentSafety", - "ConversationalLanguageUnderstanding", - "CustomVision.Prediction", - "CustomVision.Training", - "Face", - "FormRecognizer", - "HealthInsights", - "ImmersiveReader", - "Internal.AllInOne", - "LUIS", - "LUIS.Authoring", - "LanguageAuthoring", - "MetricsAdvisor", - "OpenAI", - "Personalizer", - "QnAMaker.v2", - "SpeechServices", - "TextAnalytics", - "TextTranslation" - ], - "metadata": { - "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "sku": { - "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "customSubDomainName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." - } - }, - "networkAcls": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A collection of rules governing the accessibility from specific network locations." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "allowedFqdnList": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of allowed FQDN." - } - }, - "apiProperties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The API properties for special APIs." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "dynamicThrottlingEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag to enable dynamic throttling." - } - }, - "migrationToken": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. Resource migration token." - } - }, - "restore": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." - } - }, - "restrictOutboundNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Restrict outbound network access." - } - }, - "userOwnedStorage": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The storage accounts for this resource." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "allowProjectManagement": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable project management feature for AI Foundry." - } - } - }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", - "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2025-01-31-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "cognitiveServiceNew": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]", - "kind": "[parameters('kind')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "properties": { - "allowProjectManagement": "[parameters('allowProjectManagement')]", - "customSubDomainName": "[parameters('customSubDomainName')]", - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", - "allowedFqdnList": "[parameters('allowedFqdnList')]", - "apiProperties": "[parameters('apiProperties')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", - "migrationToken": "[parameters('migrationToken')]", - "restore": "[parameters('restore')]", - "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", - "userOwnedStorage": "[parameters('userOwnedStorage')]", - "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "cognitiveServiceExisting": { - "condition": "[variables('useExistingService')]", - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", - "name": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "cognitive_service_dependencies": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "deployments": { - "value": "[parameters('deployments')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" - }, - "sku": { - "value": "[parameters('sku')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "8864856500234357706" - } - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", + "existing_cognitive_service_dependencies": { + "condition": "[variables('useExistingService')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, - "groupId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } } } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } } }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "memberName": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } } }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." } } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services account." }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" + }, + "resourceId": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The resource ID of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } + "subscriptionId": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } + "endpoint": { + "type": "string", + "metadata": { + "description": "The service endpoint of the cognitive services account." }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" + }, + "endpoints": { + "$ref": "#/definitions/endpointType", "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" + }, + "location": { + "type": "string", "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } - } + "description": "The location the resource was deployed into." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "description": "The private endpoints of the congitive services account." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" + } + } + } + }, + "dependsOn": [ + "avmContainerApp", + "avmContainerApp_Workflow", + "avmManagedIdentity", + "logAnalyticsWorkspace" + ] + }, + "cognitiveServicePrivateEndpoint": { + "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": { + "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", + "properties": { + "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", + "groupIds": [ + "account" + ] } } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "name": "ai-services-dns-zone-cognitiveservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } + { + "name": "ai-services-dns-zone-openai", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + { + "name": "ai-services-dns-zone-aiservices", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-contentunderstanding", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" } - } + ] + } + }, + "subnetResourceId": { + "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" }, - "privateEndpointSingleServiceType": { + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + "description": "Optional. The name of the Private DNS Zone Group." } }, - "applicationSecurityGroupResourceIds": { + "privateDnsZoneGroupConfigs": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/privateDnsZoneGroupConfigType" }, - "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + "description": "Optional. Specify the name of lock." } }, - "lock": { - "$ref": "#/definitions/lockType", + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { "description": "Optional. Specify the type of lock." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, + "notes": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Specify the notes of the lock." } - }, - "tags": { - "type": "object", + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + "description": "Optional. The name of the private DNS zone group config." } }, - "enableTelemetry": { - "type": "bool", - "nullable": true, + "privateDnsZoneResourceId": { + "type": "string", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. The resource id of the private DNS zone." } } }, "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "description": "The type of a private DNS zone group configuration.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "private-dns-zone-group/main.bicep" } } }, @@ -38339,96 +42198,70 @@ "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account." + "description": "Required. Name of the private endpoint resource to create." } }, - "sku": { + "subnetResourceId": { "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "tags": { - "type": "object", + "customNetworkInterfaceName": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "deployments": { + "ipConfigurations": { "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." }, - "nullable": true, + "nullable": true + }, + "ipVersionType": { + "type": "string", "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "nullable": true, "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. Location for all Resources." } }, "lock": { @@ -38448,33 +42281,51 @@ "description": "Optional. Array of role assignments to create." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." }, - "nullable": true, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", "metadata": { - "description": "Optional. The diagnostic settings of the service." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true }, - "projectName": { - "type": "string", + "manualPrivateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Optional: Name for the project which needs to be created." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true }, - "projectDescription": { - "type": "string", + "privateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Optional: Description for the project which needs to be created." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + "description": "Optional. Enable/Disable usage telemetry for module." } } }, @@ -38487,121 +42338,89 @@ } ], "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } }, "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" - }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" - }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" - }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { "copy": [ { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" } } ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" } }, - "cognitiveService_roleAssignments": { + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { "copy": { - "name": "cognitiveService_roleAssignments", + "name": "privateEndpoint_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -38610,18 +42429,16 @@ "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } - }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -38629,42 +42446,13 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "privateEndpointName": { + "value": "[parameters('name')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" } }, "template": { @@ -38675,74 +42463,12 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "18436885663402767850" + "templateHash": "9935179114830442414" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." }, "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, "privateDnsZoneGroupConfigType": { "type": "object", "properties": { @@ -38759,545 +42485,1094 @@ "description": "Required. The resource id of the private DNS zone." } } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." } } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { + "privateEndpointName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "applicationSecurityGroupResourceIds": { + "privateDnsZoneConfigs": { "type": "array", "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + "$ref": "#/definitions/privateDnsZoneGroupConfigType" }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, + "minLength": 1, + "maxLength": 5, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." } }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "defaultValue": "default", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "Optional. The name of the private DNS zone group." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, "privateEndpoint": { + "existing": true, "type": "Microsoft.Network/privateEndpoints", "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { "copy": [ { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } } } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" + ] } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[parameters('name')]" }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "avmAiServices", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", + "virtualNetwork" + ] + }, + "avmContainerAppEnv": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('cae-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", + "workloadProfiles": { + "value": [ + { + "name": "Consumption", + "workloadProfileType": "Consumption" + } + ] + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "platformReservedCidr": { + "value": "172.17.17.0/24" + }, + "platformReservedDnsIP": { + "value": "172.17.17.17" + }, + "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", + "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11924518395502120940" + }, + "name": "App ManagedEnvironments", + "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." + }, + "definitions": { + "certificateType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the certificate." + } + }, + "certificateType": { + "type": "string", + "allowedValues": [ + "ImagePullTrustedCA", + "ServerSSLCertificate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location for the resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a certificate." + } + }, + "storageType": { + "type": "object", + "properties": { + "accessMode": { + "type": "string", + "allowedValues": [ + "ReadOnly", + "ReadWrite" + ], + "metadata": { + "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. File share name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the storage." + } + }, + "appLogsConfigurationType": { + "type": "object", + "discriminator": { + "propertyName": "destination", + "mapping": { + "azure-monitor": { + "$ref": "#/definitions/appLogsConfigurationMonitorType" + }, + "log-analytics": { + "$ref": "#/definitions/appLogsConfigurationLawType" + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the App Logs Configuration." + } + }, + "appLogsConfigurationMonitorType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "azure-monitor" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using azure-monitor." + } + }, + "appLogsConfigurationLawType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "log-analytics" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Existing Log Analytics Workspace resource ID." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using log-analytics." + } + }, + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } + }, + "metadata": { + "description": "The type for the certificate's key vault properties.", + "__bicep_imported_from!": { + "sourceTemplate": "certificate/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string." + } + }, + "daprConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" + }, + "description": "Optional. The configuration of Dapr component." + }, + "nullable": true + }, + "ingressConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" + }, + "description": "Optional. Ingress configuration for the Managed Environment." + }, + "nullable": true + }, + "kedaConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" + }, + "description": "Optional. The configuration of Keda component." + }, + "nullable": true + }, + "peerAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" + }, + "description": "Optional. Peer authentication settings for the Managed Environment." + }, + "nullable": true + }, + "daprAIConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." + } + }, + "daprAIInstrumentationKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." + } + }, + "dockerBridgeCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "infrastructureSubnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "internal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedDnsIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "peerTrafficEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not to encrypt peer traffic." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether to allow or block all public traffic." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not this Managed Environment is zone-redundant." + } + }, + "certificatePassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Password of the certificate used by the custom domain." + } + }, + "certificateValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Certificate to use for the custom domain. PFX or PEM." + } + }, + "dnsSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. DNS suffix for the environment domain." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "openTelemetryConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" + }, + "description": "Optional. Open Telemetry configuration." + }, + "nullable": true + }, + "workloadProfiles": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" + }, + "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." + }, + "nullable": true + }, + "infrastructureResourceGroupName": { + "type": "string", + "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", + "metadata": { + "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "storages": { + "type": "array", + "items": { + "$ref": "#/definitions/storageType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of storages to mount on the environment." + } + }, + "certificate": { + "$ref": "#/definitions/certificateType", + "nullable": true, + "metadata": { + "description": "Optional. A Managed Environment Certificate." + } + }, + "appLogsConfiguration": { + "$ref": "#/definitions/appLogsConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The AppLogsConfiguration for the Managed Environment." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-11-01", + "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } + } + } + } + }, + "logAnalyticsWorkspace": { + "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-02-01", + "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" + }, + "managedEnvironment": { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "appInsightsConfiguration": { + "connectionString": "[parameters('appInsightsConnectionString')]" + }, + "daprConfiguration": "[parameters('daprConfiguration')]", + "ingressConfiguration": "[parameters('ingressConfiguration')]", + "kedaConfiguration": "[parameters('kedaConfiguration')]", + "peerAuthentication": "[parameters('peerAuthentication')]", + "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", + "daprAIConnectionString": "[parameters('daprAIConnectionString')]", + "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", + "customDomainConfiguration": { + "certificatePassword": "[parameters('certificatePassword')]", + "certificateValue": "[parameters('certificateValue')]", + "dnsSuffix": "[parameters('dnsSuffix')]", + "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" + }, + "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", + "peerTrafficConfiguration": { + "encryption": { + "enabled": "[parameters('peerTrafficEncryption')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "vnetConfiguration": { + "internal": "[parameters('internal')]", + "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", + "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", + "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", + "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" + }, + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]", + "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "managedEnvironment_roleAssignments": { + "copy": { + "name": "managedEnvironment_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_storage": { + "copy": { + "name": "managedEnvironment_storage", + "count": "[length(coalesce(parameters('storages'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" }, - "outputs": { - "resourceGroupName": { + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "kind": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + }, + "accessMode": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + }, + "storageAccountName": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "945327737463253676" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "parameters": { + "name": { "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" + "description": "Required. The name of the file share." + } }, - "resourceId": { + "managedEnvironmentName": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } }, - "name": { + "accessMode": { "type": "string", "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" + "description": "Required. The access mode for the storage." + } }, - "location": { + "kind": { "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } }, - "customDnsConfigs": { - "type": "array", + "storageAccountName": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." + "description": "Required. Storage account name." + } + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "storage": { + "type": "Microsoft.App/managedEnvironments/storages", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "properties": { + "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", + "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the file share." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[parameters('name')]" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "resourceId": { + "type": "string", "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The resource ID of the file share." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" }, - "groupId": { + "resourceGroupName": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The resource group the file share was deployed into." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[resourceGroup().name]" } } } - } + }, + "dependsOn": [ + "managedEnvironment" + ] }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "managedEnvironment_certificate": { + "condition": "[not(empty(parameters('certificate')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + "name": { + "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "certificateKeyVaultProperties": { + "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" + }, + "certificateType": { + "value": "[tryGet(parameters('certificate'), 'certificateType')]" + }, + "certificateValue": { + "value": "[tryGet(parameters('certificate'), 'certificateValue')]" + }, + "certificatePassword": { + "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" + }, + "location": { + "value": "[tryGet(parameters('certificate'), 'location')]" + }, + "tags": { + "value": "[tryGet(parameters('certificate'), 'tags')]" } }, "template": { @@ -39307,128 +43582,564 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "312284397710022090" - } + "version": "0.42.1.51946", + "templateHash": "574133184207535827" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." }, "definitions": { - "secretSetOutputType": { + "certificateKeyVaultPropertiesType": { "type": "object", "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { + "identityResourceId": { "type": "string", "metadata": { - "description": "The secret URI of the exported secret." + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." } }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { + "keyVaultUrl": { "type": "string", "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." } } }, "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for the certificate's key vault properties." } } }, "parameters": { - "keyVaultName": { + "name": { "type": "string", "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." + "description": "Required. Name of the Container Apps Managed Environment Certificate." } }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, + "managedEnvironmentName": { + "type": "string", "metadata": { - "description": "Required. The secrets to set in the Key Vault." + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference to the certificate to use for the custom domain." + } + }, + "certificateType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ServerSSLCertificate", + "ImagePullTrustedCA" + ], + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true } }, "resources": { - "keyVault": { + "managedEnvironment": { "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "managedEnvironmentCertificate": { + "type": "Microsoft.App/managedEnvironments/certificates", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", + "certificateType": "[parameters('certificateType')]", + "password": "[parameters('certificatePassword')]", + "value": "[parameters('certificateValue')]" + }, + "tags": "[parameters('tags')]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } + "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the certificate was deployed into." + }, + "value": "[resourceGroup().name]" } + } + } + }, + "dependsOn": [ + "managedEnvironment" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Managed Environment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Managed Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Managed Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('managedEnvironment').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The IP address of the Managed Environment." + }, + "value": "[reference('managedEnvironment').staticIp]" + }, + "domainVerificationId": { + "type": "string", + "metadata": { + "description": "The domain verification id for custom domains." + }, + "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "virtualNetwork" + ] + }, + "avmContainerRegistryReader": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } } } }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -39436,196 +44147,158 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" }, - "aiServicesName": { + "userAssignedIdentityName": { "value": "[parameters('name')]" }, - "location": { - "value": "[parameters('location')]" + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" }, - "tags": { - "value": "[parameters('tags')]" + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "276675105610077046" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } - } + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." }, "parameters": { - "name": { + "userAssignedIdentityName": { "type": "string", "metadata": { - "description": "Required. Name of the AI Services project." + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." } }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The location of the Project resource." + "description": "Required. The name of the secret." } }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", + "audiences": { + "type": "array", "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." } }, - "aiServicesName": { + "issuer": { "type": "string", "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." } }, - "azureExistingAIProjectResourceId": { + "subject": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." } } }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" - }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" } } - }, + ], "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", + "name": { + "type": "string", "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." + "description": "The name of the federated identity credential." }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" } } } - } + }, + "dependsOn": [ + "userAssignedIdentity" + ] } }, "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", + "name": { + "type": "string", "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + "description": "The name of the user assigned identity." }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + "value": "[parameters('name')]" }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", "metadata": { - "description": "The private endpoints of the congitive services account." + "description": "The principal ID (object ID) of the user assigned identity." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } + "value": "[reference('userAssignedIdentity').principalId]" }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" } } } - }, - "dependsOn": [ - "cognitiveServiceNew" - ] + } }, - "existing_cognitive_service_dependencies": { - "condition": "[variables('useExistingService')]", + "avmContainerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -39633,40 +44306,87 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[variables('existingCognitiveServiceDetails')[8]]" + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" }, - "projectName": { - "value": "[parameters('projectName')]" + "location": { + "value": "[parameters('location')]" }, - "projectDescription": { - "value": "[parameters('projectDescription')]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('existingFoundryProjectResourceId')]" + "workloadProfileName": { + "value": "Consumption" }, - "location": { - "value": "[parameters('location')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "deployments": { - "value": "[parameters('deployments')]" + "registries": { + "value": null }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } }, - "lock": { - "value": "[parameters('lock')]" + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" + "activeRevisionsMode": { + "value": "Single" }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" + "ingressExternal": { + "value": false }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" + "disableIngress": { + "value": true }, - "sku": { - "value": "[parameters('sku')]" + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } }, "tags": { "value": "[parameters('tags')]" @@ -39679,434 +44399,557 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "8864856500234357706" - } + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." }, "definitions": { - "privateEndpointOutputType": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "Required. The name of the service." } }, - "resourceId": { + "serviceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." } }, - "groupId": { + "secretRef": { "type": "string", "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." } }, - "customDnsConfigs": { + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { "type": "array", "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" }, + "nullable": true, "metadata": { - "description": "The custom DNS configurations of the private endpoint." + "description": "Optional. Specifies the content for the access-control-allow-origins header." } }, - "networkInterfaceResourceIds": { + "exposeHeaders": { "type": "array", "items": { "type": "string" }, + "nullable": true, "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." } } }, "metadata": { "__bicep_export!": true, - "description": "The type for the private endpoint output." + "description": "The type for a CORS policy." } }, - "deploymentType": { + "containerAppProbeHttpGetType": { "type": "object", "properties": { - "name": { + "host": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." + "description": "Optional. Host name to connect to. Defaults to the pod IP." } }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" }, + "nullable": true, "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." + "description": "Optional. HTTP headers to set in the request." } }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, + "path": { + "type": "string", "metadata": { - "description": "Optional. The resource model definition representing SKU." + "description": "Required. Path to access on the HTTP server." } }, - "raiPolicyName": { - "type": "string", - "nullable": true, + "port": { + "type": "int", "metadata": { - "description": "Optional. The name of RAI policy." + "description": "Required. Name or number of the port to access on the container." } }, - "versionUpgradeOption": { + "scheme": { "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], "nullable": true, "metadata": { - "description": "Optional. The version upgrade option." + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." + "description": "The type for a container app probe HTTP GET." } }, - "endpointType": { + "containerAppProbeHttpGetHeadersItemType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Type of the endpoint." + "description": "Required. Name of the header." } }, - "endpoint": { + "value": { "type": "string", - "nullable": true, "metadata": { - "description": "The endpoint URI." + "description": "Required. Value of the header." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." + "description": "The type for a container app probe HTTP GET header." } }, - "secretsExportConfigurationType": { + "containerAppProbeTcpSocketType": { "type": "object", "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { + "host": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." + "description": "Optional. Host name to connect to, defaults to the pod IP." } }, - "accessKey2Name": { - "type": "string", - "nullable": true, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." + "description": "The type for a container app probe TCP socket." } }, - "_1.privateEndpointCustomDnsConfigType": { + "scaleType": { "type": "object", "properties": { - "fqdn": { - "type": "string", + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. The cooldown period in seconds." } }, - "ipAddresses": { + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/scaleRuleType" }, + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. The scaling rules." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The scale settings for the Container App." } }, - "_1.privateEndpointIpConfigurationType": { + "scaleRuleType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. The name of the scaling rule." } }, - "properties": { + "custom": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The scaling rules for the Container App." } }, - "_1.privateEndpointPrivateDnsZoneGroupType": { + "volumeMountType": { "type": "object", "properties": { - "name": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, + "volumeName": { + "type": "string", "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + "description": "Required. This must match the Name of a Volume." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The type for a volume mount." } }, - "_1.secretSetOutputType": { + "secretType": { "type": "object", "properties": { - "secretResourceId": { + "identity": { "type": "string", + "nullable": true, "metadata": { - "description": "The resourceId of the exported secret." + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." } }, - "secretUri": { + "keyVaultUrl": { "type": "string", + "nullable": true, "metadata": { - "description": "The secret URI of the exported secret." + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." } }, - "secretUriWithVersion": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "The secret URI with version of the exported secret." + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." } } }, "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for a secret." } }, - "aiProjectOutputType": { + "authConfigType": { "type": "object", "properties": { - "name": { - "type": "string", + "encryptionSettings": { + "type": "object", "metadata": { - "description": "Required. Name of the AI project." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "resourceId": { - "type": "string", + "globalValidation": { + "type": "object", "metadata": { - "description": "Required. Resource ID of the AI project." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true }, - "apiEndpoint": { - "type": "string", + "httpSettings": { + "type": "object", "metadata": { - "description": "Required. API endpoint for the AI project." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true } }, "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." } }, - "diagnosticSettingFullType": { + "diagnosticSettingMetricsOnlyType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Optional. The name of diagnostic setting." } }, "metricCategories": { @@ -40182,9 +45025,9 @@ } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -40221,152 +45064,35 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "privateEndpointSingleServiceType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { + "systemAssigned": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "applicationSecurityGroupResourceIds": { + "userAssignedResourceIds": { "type": "array", "items": { "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -40441,99 +45167,170 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." } - } - }, - "parameters": { - "name": { + }, + "clientCertificateMode": { "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], "metadata": { - "description": "Required. The name of Cognitive Services account." + "description": "Optional. Client certificate mode for mTLS." } }, - "sku": { + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { "type": "string", - "defaultValue": "S0", + "defaultValue": "none", "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" + "none", + "sticky" ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Optional. Bool indicating if the Container App should enable session affinity." } }, - "location": { + "ingressTransport": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Ingress transport protocol." } }, - "tags": { + "service": { "type": "object", - "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." } }, - "deployments": { + "additionalPortMappings": { "type": "array", "items": { - "$ref": "#/definitions/deploymentType" + "$ref": "#/definitions/ingressPortMappingType" }, "nullable": true, "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." + "description": "Optional. Settings to expose additional ports on container app." } }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } }, - "privateEndpoints": { + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" + "$ref": "#/definitions/serviceBindingType" }, "nullable": true, "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." } }, "lock": { @@ -40543,529 +45340,457 @@ "description": "Optional. The lock settings of the service." } }, - "roleAssignments": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The managed identity definition for this resource." } }, - "diagnosticSettings": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." } }, - "projectName": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional: Name for the project which needs to be created." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "projectDescription": { - "type": "string", + "customDomains": { + "type": "array", "metadata": { - "description": "Optional: Description for the project which needs to be created." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." } }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", + "ipSecurityRestrictions": { + "type": "array", "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." } - ], - "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." } }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." } }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." } }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" }, - "customNetworkInterfaceName": { + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." } }, - "ipConfigurations": { - "type": "array", + "encryptionSettings": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "ipVersionType": { - "type": "string", + "globalValidation": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } + "nullable": true }, - "tags": { + "httpSettings": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "customDnsConfigs": { - "type": "array", + "identityProviders": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" }, - "description": "Optional. Custom DNS configurations." + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "manualPrivateLinkServiceConnections": { - "type": "array", + "login": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." }, "nullable": true }, - "privateLinkServiceConnections": { - "type": "array", + "platform": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." }, "nullable": true }, @@ -41077,33 +45802,12 @@ } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -41119,2158 +45823,1811 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "current" }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceGroup().name]" } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" + ] + }, + "avmContainerApp_API": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" } } } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." } }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "serviceBindingType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "312284397710022090" - } + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." - } + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "lockType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "276675105610077046" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services project." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. The location of the Project resource." - } - }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } - }, - "aiServicesName": { - "type": "string", - "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" - } - } - }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" - }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" - } - } - }, - "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." - }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } - } - } - } + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." } - } - }, - "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + "nullable": true }, - "privateEndpoints": { + "secrets": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "$ref": "#/definitions/secretType" }, + "nullable": true, "metadata": { - "description": "The private endpoints of the congitive services account." + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." } }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The service endpoint of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" - }, - "endpoints": { - "$ref": "#/definitions/endpointType", - "metadata": { - "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "logAnalyticsWorkspace" - ] - }, - "cognitiveServicePrivateEndpoint": { - "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "customNetworkInterfaceName": { - "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" - }, - "privateLinkServiceConnections": { - "value": [ - { - "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", - "properties": { - "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", - "groupIds": [ - "account" - ] - } - } - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDnsZoneGroupConfigs": [ - { - "name": "ai-services-dns-zone-cognitiveservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-openai", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-aiservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-contentunderstanding", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" - } - ] - } - }, - "subnetResourceId": { - "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "enableReferencedModulesTelemetry": false }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } } }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } + "dependsOn": [ + "containerApp" + ] }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "avmAiServices", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", - "virtualNetwork" - ] - }, - "avmContainerAppEnv": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('cae-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", - "workloadProfiles": { - "value": [ - { - "name": "Consumption", - "workloadProfileType": "Consumption" - } - ] - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "publicNetworkAccess": { - "value": "Enabled" - }, - "platformReservedCidr": { - "value": "172.17.17.0/24" - }, - "platformReservedDnsIP": { - "value": "172.17.17.17" - }, - "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", - "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.containersSubnetResourceId.value), createObject('value', null()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "11924518395502120940" - }, - "name": "App ManagedEnvironments", - "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." - }, - "definitions": { - "certificateType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the certificate." - } - }, - "certificateType": { - "type": "string", - "allowedValues": [ - "ImagePullTrustedCA", - "ServerSSLCertificate" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the certificate." - } - }, - "certificateValue": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." - } - }, - "certificatePassword": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The password of the certificate." - } - }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", - "nullable": true, - "metadata": { - "description": "Optional. A key vault reference." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location for the resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a certificate." - } - }, - "storageType": { - "type": "object", - "properties": { - "accessMode": { - "type": "string", - "allowedValues": [ - "ReadOnly", - "ReadWrite" - ], - "metadata": { - "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Required. Storage account name." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. File share name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the storage." - } - }, - "appLogsConfigurationType": { - "type": "object", - "discriminator": { - "propertyName": "destination", - "mapping": { - "azure-monitor": { - "$ref": "#/definitions/appLogsConfigurationMonitorType" - }, - "log-analytics": { - "$ref": "#/definitions/appLogsConfigurationLawType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the App Logs Configuration." - } - }, - "appLogsConfigurationMonitorType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "azure-monitor" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using azure-monitor." - } - }, - "appLogsConfigurationLawType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "log-analytics" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - }, - "logAnalyticsWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Existing Log Analytics Workspace resource ID." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using log-analytics." - } - }, - "certificateKeyVaultPropertiesType": { - "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } - }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } - }, - "metadata": { - "description": "The type for the certificate's key vault properties.", - "__bicep_imported_from!": { - "sourceTemplate": "certificate/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container Apps Managed Environment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "appInsightsConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string." - } - }, - "daprConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" - }, - "description": "Optional. The configuration of Dapr component." - }, - "nullable": true - }, - "ingressConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" - }, - "description": "Optional. Ingress configuration for the Managed Environment." - }, - "nullable": true - }, - "kedaConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" - }, - "description": "Optional. The configuration of Keda component." - }, - "nullable": true - }, - "peerAuthentication": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" - }, - "description": "Optional. Peer authentication settings for the Managed Environment." - }, - "nullable": true - }, - "daprAIConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." - } - }, - "daprAIInstrumentationKey": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." - } - }, - "dockerBridgeCidr": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "infrastructureSubnetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "internal": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "platformReservedCidr": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "platformReservedDnsIP": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "peerTrafficEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not to encrypt peer traffic." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether to allow or block all public traffic." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not this Managed Environment is zone-redundant." - } - }, - "certificatePassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Password of the certificate used by the custom domain." - } - }, - "certificateValue": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. Certificate to use for the custom domain. PFX or PEM." - } - }, - "dnsSuffix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. DNS suffix for the environment domain." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "openTelemetryConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" - }, - "description": "Optional. Open Telemetry configuration." - }, - "nullable": true - }, - "workloadProfiles": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" - }, - "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." - }, - "nullable": true - }, - "infrastructureResourceGroupName": { - "type": "string", - "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", - "metadata": { - "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "storages": { - "type": "array", - "items": { - "$ref": "#/definitions/storageType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of storages to mount on the environment." - } - }, - "certificate": { - "$ref": "#/definitions/certificateType", - "nullable": true, - "metadata": { - "description": "Optional. A Managed Environment Certificate." - } - }, - "appLogsConfiguration": { - "$ref": "#/definitions/appLogsConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The AppLogsConfiguration for the Managed Environment." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-11-01", - "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } - } - }, - "logAnalyticsWorkspace": { - "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", - "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" - }, - "managedEnvironment": { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "appInsightsConfiguration": { - "connectionString": "[parameters('appInsightsConnectionString')]" - }, - "daprConfiguration": "[parameters('daprConfiguration')]", - "ingressConfiguration": "[parameters('ingressConfiguration')]", - "kedaConfiguration": "[parameters('kedaConfiguration')]", - "peerAuthentication": "[parameters('peerAuthentication')]", - "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", - "daprAIConnectionString": "[parameters('daprAIConnectionString')]", - "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", - "customDomainConfiguration": { - "certificatePassword": "[parameters('certificatePassword')]", - "certificateValue": "[parameters('certificateValue')]", - "dnsSuffix": "[parameters('dnsSuffix')]", - "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" - }, - "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", - "peerTrafficConfiguration": { - "encryption": { - "enabled": "[parameters('peerTrafficEncryption')]" - } - }, - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "vnetConfiguration": { - "internal": "[parameters('internal')]", - "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", - "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", - "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", - "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" - }, - "workloadProfiles": "[parameters('workloadProfiles')]", - "zoneRedundant": "[parameters('zoneRedundant')]", - "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "managedEnvironment_roleAssignments": { - "copy": { - "name": "managedEnvironment_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "managedEnvironment" + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] }, - "managedEnvironment_storage": { - "copy": { - "name": "managedEnvironment_storage", - "count": "[length(coalesce(parameters('storages'), createArray()))]" - }, + "avmContainerApp_Web": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -43278,19 +47635,110 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" + "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" }, - "managedEnvironmentName": { - "value": "[parameters('name')]" + "location": { + "value": "[parameters('location')]" }, - "kind": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" }, - "accessMode": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 3000 + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } }, - "storageAccountName": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + "containers": { + "value": [ + { + "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_API_BASE_URL", + "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" + }, + { + "name": "APP_WEB_CLIENT_ID", + "value": "" + }, + { + "name": "APP_WEB_AUTHORITY", + "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" + }, + { + "name": "APP_WEB_SCOPE", + "value": "" + }, + { + "name": "APP_API_SCOPE", + "value": "" + }, + { + "name": "APP_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_POST_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_CONSOLE_LOG_ENABLED", + "value": "false" + } + ] + } + ] } }, "template": { @@ -43301,3965 +47749,3227 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "945327737463253676" + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the file share." + "description": "Required. Name of the Container App." } }, - "managedEnvironmentName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "description": "Optional. Location for all Resources." } }, - "accessMode": { + "kind": { "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], "metadata": { - "description": "Required. The access mode for the storage." + "description": "Optional. Metadata used to render different experiences for resources of the same type." } }, - "kind": { + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { "type": "string", + "defaultValue": "ignore", "allowedValues": [ - "NFS", - "SMB" + "accept", + "ignore", + "require" ], "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." } }, - "storageAccountName": { + "stickySessionsAffinity": { "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], "metadata": { - "description": "Required. Storage account name." + "description": "Optional. Bool indicating if the Container App should enable session affinity." } - } - }, - "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" }, - "storage": { - "type": "Microsoft.App/managedEnvironments/storages", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", - "properties": { - "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", - "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." } - } - }, - "outputs": { - "name": { + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { "type": "string", "metadata": { - "description": "The name of the file share." - }, - "value": "[parameters('name')]" + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } }, - "resourceId": { - "type": "string", + "ipSecurityRestrictions": { + "type": "array", "metadata": { - "description": "The resource ID of the file share." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." }, - "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" + "nullable": true }, - "resourceGroupName": { - "type": "string", + "traffic": { + "type": "array", "metadata": { - "description": "The resource group the file share was deployed into." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_certificate": { - "condition": "[not(empty(parameters('certificate')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" - }, - "managedEnvironmentName": { - "value": "[parameters('name')]" - }, - "certificateKeyVaultProperties": { - "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" - }, - "certificateType": { - "value": "[tryGet(parameters('certificate'), 'certificateType')]" - }, - "certificateValue": { - "value": "[tryGet(parameters('certificate'), 'certificateValue')]" - }, - "certificatePassword": { - "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" - }, - "location": { - "value": "[tryGet(parameters('certificate'), 'location')]" - }, - "tags": { - "value": "[tryGet(parameters('certificate'), 'tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "574133184207535827" + "nullable": true }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." - }, - "definitions": { - "certificateKeyVaultPropertiesType": { + "dapr": { "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } + "description": "Optional. Dapr configuration for the Container App." }, + "nullable": true + }, + "identitySettings": { + "type": "array", "metadata": { - "__bicep_export!": true, - "description": "The type for the certificate's key vault properties." - } - } - }, - "parameters": { - "name": { - "type": "string", + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, "metadata": { - "description": "Required. Name of the Container Apps Managed Environment Certificate." + "description": "Optional. Max inactive revisions a Container App can have." } }, - "managedEnvironmentName": { - "type": "string", + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. The termination grace period for the container app." } }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, "nullable": true, "metadata": { - "description": "Optional. A key vault reference to the certificate to use for the custom domain." + "description": "Optional. The secrets of the Container App." } }, - "certificateType": { + "revisionSuffix": { "type": "string", "nullable": true, - "allowedValues": [ - "ServerSSLCertificate", - "ImagePullTrustedCA" - ], "metadata": { - "description": "Optional. The type of the certificate." + "description": "Optional. User friendly suffix that is appended to the revision name." } }, - "certificateValue": { + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." + "description": "Optional. Workload profile name to pin for container app execution." } }, - "certificatePassword": { - "type": "securestring", + "authConfig": { + "$ref": "#/definitions/authConfigType", "nullable": true, "metadata": { - "description": "Optional. The password of the certificate." + "description": "Optional. The name of the Container App Auth configs." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "managedEnvironmentCertificate": { - "type": "Microsoft.App/managedEnvironments/certificates", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", "location": "[parameters('location')]", + "identity": "[variables('identity')]", "properties": { - "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", - "certificateType": "[parameters('certificateType')]", - "password": "[parameters('certificatePassword')]", - "value": "[parameters('certificateValue')]" - }, - "tags": "[parameters('tags')]" - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key values." + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "value": "[parameters('name')]" + "dependsOn": [ + "containerApp" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key values." + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, - "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + "dependsOn": [ + "containerApp" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the certificate was deployed into." + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Managed Environment was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Managed Environment." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Managed Environment." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" - }, - "defaultDomain": { - "type": "string", - "metadata": { - "description": "The Default domain of the Managed Environment." - }, - "value": "[reference('managedEnvironment').defaultDomain]" - }, - "staticIp": { - "type": "string", - "metadata": { - "description": "The IP address of the Managed Environment." - }, - "value": "[reference('managedEnvironment').staticIp]" - }, - "domainVerificationId": { - "type": "string", - "metadata": { - "description": "The domain verification id for custom domains." - }, - "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "avmContainerRegistryReader": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." - }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "isolationScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], - "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" - }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" - }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" - }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "1387931959101373036" + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } }, - "parameters": { - "userAssignedIdentityName": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." - } + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "Required. The name of the secret." - } - }, - "audiences": { - "type": "array", - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." - } + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "issuer": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." - } + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." - } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" - } - } - ], - "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the federated identity credential." + "description": "The name of the Container App." }, "value": "[parameters('name')]" }, - "resourceId": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource ID of the federated identity credential." + "description": "The principal ID of the system assigned identity." }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The name of the resource group the federated identity credential was created in." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } }, "dependsOn": [ - "userAssignedIdentity" + "avmContainerApp_API", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - }, - "avmContainerApp": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" + "avmContainerApp_Workflow": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" + "location": { + "value": "[parameters('location')]" }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + "workloadProfileName": { + "value": "Consumption" }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" + "registries": { + "value": null }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "tags": { + "value": "[parameters('tags')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "activeRevisionsMode": { + "value": "Single" }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } } }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "name": "Container Apps", + "description": "This module deploys a Container App." }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Required. Name of the Container App." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Location for all Resources." + } }, - "globalValidation": { - "type": "object", + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } }, - "httpSettings": { - "type": "object", + "disableIngress": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Bool to disable all ingress traffic for the container app." + } }, - "identityProviders": { - "type": "object", + "ingressExternal": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } }, - "login": { + "service": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "description": "Optional. Dev ContainerApp service type." }, "nullable": true }, - "platform": { - "type": "object", + "includeAddOns": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } }, - "enableTelemetry": { + "ingressAllowInsecure": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." } - } - }, - "outputs": { - "name": { + }, + "activeRevisionsMode": { "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" + "description": "Optional. Controls how active revisions are handled for the Container app." + } }, - "resourceId": { + "environmentResourceId": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "nullable": true }, - "resourceGroupName": { - "type": "string", + "registries": { + "type": "array", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_API": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 - } - ] - } - ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" - } - } - } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "containerApp" + "applicationInsights", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + "avmCosmosDB": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "mongodbDatabases": { + "value": [ + { + "name": "default", + "tag": "default database" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "databaseAccountOfferType": { + "value": "Standard" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "enableAutomaticFailover": { + "value": false }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "serverVersion": { + "value": "7.0" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "capabilitiesToAdd": { + "value": [ + "EnableMongo" + ] }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "defaultConsistencyLevel": { + "value": "Session" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } + "maxIntervalInSeconds": { + "value": 5 + }, + "maxStalenessPrefix": { + "value": 100 + }, + "zoneRedundant": { + "value": false + }, + "networkRestrictions": { + "value": { + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", + "ipRules": [], + "virtualNetworkRules": [] + } + }, + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -47268,6045 +50978,5178 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" + "version": "0.40.2.10011", + "templateHash": "1772014800591596213" + }, + "name": "Azure Cosmos DB account", + "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group ID for the private endpoint group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses for the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "failoverLocationType": { + "type": "object", + "properties": { + "failoverPriority": { + "type": "int", + "metadata": { + "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." + } + }, + "isZoneRedundant": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." + } + }, + "locationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the region." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the failover location." + } + }, + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." + } + }, + "sqlRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/nestedSqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." + } + }, + "networkRestrictionType": { + "type": "object", + "properties": { + "ipRules": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." + } + }, + "networkAclBypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." + } + }, + "publicNetworkAccess": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." + } + }, + "virtualNetworkRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of a subnet." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." + } + }, + "networkAclBypassResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network restriction." + } + }, + "gremlinDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a gremlin databae." + } }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { - "type": "string", + "mongoDbType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for a mongo databae." } }, - "encryptionSettings": { + "sqlDatabaseType": { "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "__bicep_export!": true, + "description": "The type for a sql database." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } }, - "nullable": true + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "cassandraStandaloneRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." + } }, - "globalValidation": { + "cassandraRoleDefinitionType": { "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "cassandraKeyspaceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraTableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraViewType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + } }, - "nullable": true + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB Cassandra keyspace." + } }, - "httpSettings": { + "defaultIdentityType": { "type": "object", + "discriminator": { + "propertyName": "name", + "mapping": { + "FirstPartyIdentity": { + "$ref": "#/definitions/defaultIdentityFirstPartyType" + }, + "SystemAssignedIdentity": { + "$ref": "#/definitions/defaultIdentitySystemAssignedType" + }, + "UserAssignedIdentity": { + "$ref": "#/definitions/defaultIdentityUserAssignedType" + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "__bicep_export!": true, + "description": "The type for the default identity." + } + }, + "defaultIdentityFirstPartyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "FirstPartyIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentitySystemAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "SystemAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentityUserAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "UserAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the user assigned identity to use as the default identity." + } + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "identityProviders": { + "_1.privateEndpointIpConfigurationType": { "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "login": { + "cassandraRoleAssignmentType": { "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-role-definition/main.bicep" + } + } + }, + "cassandraTableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "description": "The type of a Cassandra table.", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "tableType" + } + } + }, + "cassandraViewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } }, - "nullable": true + "metadata": { + "description": "The type of a Cassandra view (materialized view).", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "viewType" + } + } }, - "platform": { + "collectionType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "description": "The type of a collection.", + "__bicep_imported_from!": { + "sourceTemplate": "mongodb-database/main.bicep" } } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "containerType": { + "type": "object", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_Web": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "ingressExternal": { - "value": true - }, - "ingressTargetPort": { - "value": 3000 - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" - } - } - } - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_API_BASE_URL", - "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" - }, - { - "name": "APP_WEB_CLIENT_ID", - "value": "" - }, - { - "name": "APP_WEB_AUTHORITY", - "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" - }, - { - "name": "APP_WEB_SCOPE", - "value": "" - }, - { - "name": "APP_API_SCOPE", - "value": "" - }, - { - "name": "APP_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_POST_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_CONSOLE_LOG_ENABLED", - "value": "false" - } - ] - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The type of a container.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-database/main.bicep" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { - "type": "string", + "customerManagedKeyAndVaultOnlyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "encryptionSettings": { + "diagnosticSettingFullType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "graphType": { + "type": "object", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp_API", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_Workflow": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "description": "The type of a graph.", + "__bicep_imported_from!": { + "sourceTemplate": "gremlin-database/main.bicep" + } + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "nestedSqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The type for the SQL Role Assignments.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-role-definition/main.bicep", + "originalIdentifier": "sqlRoleAssignmentType" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Required. The name of the account." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Defaults to the current resource group scope location. Location for all resources." + } }, - "globalValidation": { + "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "description": "Optional. Tags for the resource." }, "nullable": true }, - "httpSettings": { - "type": "object", + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. The managed identity definition for this resource." + } }, - "identityProviders": { - "type": "object", + "databaseAccountOfferType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "description": "Optional. The offer type for the account. Defaults to \"Standard\"." + } + }, + "failoverLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/failoverLocationType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." + } }, - "login": { - "type": "object", + "zoneRedundant": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." + } }, - "platform": { - "type": "object", + "defaultConsistencyLevel": { + "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." + } }, - "enableTelemetry": { + "disableLocalAuthentication": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + }, + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions. Defaults to true." + } }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" + "enableFreeTier": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." } - } - }, - "outputs": { - "name": { - "type": "string", + }, + "enableMultipleWriteLocations": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" + "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." + } }, - "resourceId": { - "type": "string", + "disableKeyBasedMetadataWriteAccess": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." + } }, - "resourceGroupName": { + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." + } + }, + "serverVersion": { "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2", + "5.0", + "6.0", + "7.0" + ], "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmCosmosDB": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "mongodbDatabases": { - "value": [ - { - "name": "default", - "tag": "default database" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "databaseAccountOfferType": { - "value": "Standard" - }, - "enableAutomaticFailover": { - "value": false - }, - "serverVersion": { - "value": "7.0" - }, - "capabilitiesToAdd": { - "value": [ - "EnableMongo" - ] - }, - "defaultConsistencyLevel": { - "value": "Session" - }, - "maxIntervalInSeconds": { - "value": 5 - }, - "maxStalenessPrefix": { - "value": 100 - }, - "zoneRedundant": { - "value": false - }, - "networkRestrictions": { - "value": { - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", - "ipRules": [], - "virtualNetworkRules": [] - } - }, - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1772014800591596213" - }, - "name": "Azure Cosmos DB account", - "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group ID for the private endpoint group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." - } + "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." + } + }, + "sqlDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlDatabaseType" }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses for the private endpoint." - } + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "failoverLocationType": { - "type": "object", - "properties": { - "failoverPriority": { - "type": "int", - "metadata": { - "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." - } - }, - "isZoneRedundant": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." - } - }, - "locationName": { - "type": "string", - "metadata": { - "description": "Required. The name of the region." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the failover location." - } - }, - "sqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." - } - }, - "sqlRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of data actions that are allowed." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." - } - }, - "assignments": { - "type": "array", - "items": { - "$ref": "#/definitions/nestedSqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." - } - }, - "networkRestrictionType": { - "type": "object", - "properties": { - "ipRules": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." - } - }, - "networkAclBypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." - } - }, - "publicNetworkAccess": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." - } - }, - "virtualNetworkRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of a subnet." - } + }, + "mongodbDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/mongoDbType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." - } - }, - "networkAclBypassResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network restriction." - } - }, - "gremlinDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" }, - "description": "Optional. Tags of the Gremlin database resource." - }, - "nullable": true - }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a gremlin databae." - } - }, - "mongoDbType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "items": { - "$ref": "#/definitions/collectionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "autoscaleSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + "gremlinDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/gremlinDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." + } }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." - }, - "nullable": true - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." + } }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a mongo databae." - } - }, - "sqlDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + "cassandraKeyspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraKeyspaceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." + } }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a sql database." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } - }, - "cassandraStandaloneRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." - } - }, - "cassandraRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." - } - }, - "notDataActions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." - } - }, - "assignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." - } - }, - "cassandraKeyspaceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra keyspace." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraTableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." - } - }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraViewType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + "totalThroughputLimit": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." + } }, - "description": "Optional. Tags of the Cassandra keyspace resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB Cassandra keyspace." - } - }, - "defaultIdentityType": { - "type": "object", - "discriminator": { - "propertyName": "name", - "mapping": { - "FirstPartyIdentity": { - "$ref": "#/definitions/defaultIdentityFirstPartyType" - }, - "SystemAssignedIdentity": { - "$ref": "#/definitions/defaultIdentitySystemAssignedType" - }, - "UserAssignedIdentity": { - "$ref": "#/definitions/defaultIdentityUserAssignedType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the default identity." - } - }, - "defaultIdentityFirstPartyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "FirstPartyIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - } - } - }, - "defaultIdentitySystemAssignedType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "SystemAssignedIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - } - } - }, - "defaultIdentityUserAssignedType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "UserAssignedIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the user assigned identity to use as the default identity." - } - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of control plane Azure role-based access control assignments." + } + }, + "sqlRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." + } + }, + "cassandraRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings for the service." + } + }, + "capabilitiesToAdd": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless", + "EnableNoSQLVectorSearch", + "EnableNoSQLFullTextSearch", + "EnableMaterializedViews", + "DeleteAllItemsByPartitionKey" + ], + "metadata": { + "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." + } + }, + "backupPolicyType": { "type": "string", + "defaultValue": "Continuous", + "allowedValues": [ + "Periodic", + "Continuous" + ], "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." } }, - "memberName": { + "backupPolicyContinuousTier": { "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], + "metadata": { + "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." + } + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." + } + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." } }, - "privateIPAddress": { + "backupStorageRedundancy": { "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "cassandraRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-role-definition/main.bicep" - } - } - }, - "cassandraTableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "schema": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" }, - "description": "Required. Schema definition for the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + "networkRestrictions": { + "$ref": "#/definitions/networkRestrictionType", + "defaultValue": { + "ipRules": [], + "virtualNetworkRules": [], + "publicNetworkAccess": "Disabled" + }, + "metadata": { + "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." + } }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Analytical TTL for the table." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." - } - } - }, - "metadata": { - "description": "The type of a Cassandra table.", - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "tableType" - } - } - }, - "cassandraViewType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the view." - } - }, - "viewDefinition": { - "type": "string", - "metadata": { - "description": "Required. View definition (CQL statement)." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + "minimumTlsVersion": { + "type": "string", + "defaultValue": "Tls12", + "allowedValues": [ + "Tls12" + ], + "metadata": { + "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." + } }, - "description": "Optional. Tags for the view." - }, - "nullable": true - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." - } - } - }, - "metadata": { - "description": "The type of a Cassandra view (materialized view).", - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "viewType" - } - } - }, - "collectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + "enableBurstCapacity": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." + } }, - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + "enableCassandraConnector": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." + } }, - "description": "Required. ShardKey for the collection." - } - } - }, - "metadata": { - "description": "The type of a collection.", - "__bicep_imported_from!": { - "sourceTemplate": "mongodb-database/main.bicep" - } - } - }, - "containerType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + "enablePartitionMerge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." + } }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + "enablePerRegionPerPartitionAutoscale": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." + } + }, + "analyticalStorageConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" + }, + "description": "Optional. Analytical storage specific properties." + }, + "nullable": true + }, + "cors": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" + }, + "description": "Optional. The CORS policy for the Cosmos DB database account." + }, + "nullable": true }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "defaultIdentity": { + "$ref": "#/definitions/defaultIdentityType", + "defaultValue": { + "name": "FirstPartyIdentity" + }, + "metadata": { + "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." + } }, - "description": "Optional. Indexing policy of the container." + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." + } + } }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInControlPlaneRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" }, - "nullable": true - }, - "kind": { - "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - } - }, - "metadata": { - "description": "The type of a container.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-database/main.bicep" - } - } - }, - "customerManagedKeyAndVaultOnlyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } + } + }, + "cMKKeyVault": { + "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" + }, + "databaseAccount": { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", + "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", + "dependsOn": [ + "cMKKeyVault::cMKKey" + ] + }, + "databaseAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_diagnosticSettings": { + "copy": { + "name": "databaseAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_roleAssignments": { + "copy": { + "name": "databaseAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlDatabases": { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "3972888645334640168" + }, + "name": "DocumentDB Database Account SQL Databases", + "description": "This module deploys a SQL Database in a CosmosDB Account." + }, + "definitions": { + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a container." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "container": { + "copy": { + "name": "container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "conflictResolutionPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + }, + "defaultTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "kind": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + }, + "paths": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + }, + "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", + "uniqueKeyPolicyKeys": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "4781880351108045502" + }, + "name": "DocumentDB Database Account SQL Database Containers", + "description": "This module deploys a SQL Database Container in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "variables": { + "copy": [ + { + "name": "partitionKeyPaths", + "count": "[length(parameters('paths'))]", + "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + } + ] + }, + "resources": { + "databaseAccount::sqlDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "container": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "graphType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + "databaseAccount_sqlRoleDefinitions": { + "copy": { + "name": "databaseAccount_sqlRoleDefinitions", + "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "dataActions": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" + }, + "roleName": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "sqlRoleAssignments": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "8514367433037227852" + }, + "name": "DocumentDB Database Account SQL Role Definitions.", + "description": "This module deploys a SQL Role Definision in a CosmosDB Account." + }, + "definitions": { + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SQL Role Assignments." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionIdOrName": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The role name of the SQL Role Definition." + }, + "value": "[reference('sqlRoleDefinition').roleName]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true - } - }, - "metadata": { - "description": "The type of a graph.", - "__bicep_imported_from!": { - "sourceTemplate": "gremlin-database/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "nestedSqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "description": "The type for the SQL Role Assignments.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-role-definition/main.bicep", - "originalIdentifier": "sqlRoleAssignmentType" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionIdOrName": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_sqlDatabases", + "databaseAccount_sqlRoleDefinitions" + ] }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the account." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Defaults to the current resource group scope location. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the resource." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "databaseAccountOfferType": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard" - ], - "metadata": { - "description": "Optional. The offer type for the account. Defaults to \"Standard\"." - } - }, - "failoverLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/failoverLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." - } - }, - "defaultConsistencyLevel": { - "type": "string", - "defaultValue": "Session", - "allowedValues": [ - "Eventual", - "ConsistentPrefix", - "Session", - "BoundedStaleness", - "Strong" - ], - "metadata": { - "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." - } - }, - "disableLocalAuthentication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." - } - }, - "enableAnalyticalStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." - } - }, - "enableAutomaticFailover": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable automatic failover for regions. Defaults to true." - } - }, - "enableFreeTier": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." - } - }, - "enableMultipleWriteLocations": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." - } - }, - "disableKeyBasedMetadataWriteAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." - } - }, - "maxStalenessPrefix": { - "type": "int", - "defaultValue": 100000, - "minValue": 1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." - } - }, - "maxIntervalInSeconds": { - "type": "int", - "defaultValue": 300, - "minValue": 5, - "maxValue": 86400, - "metadata": { - "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." - } - }, - "serverVersion": { - "type": "string", - "defaultValue": "4.2", - "allowedValues": [ - "3.2", - "3.6", - "4.0", - "4.2", - "5.0", - "6.0", - "7.0" - ], - "metadata": { - "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." - } - }, - "sqlDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlDatabaseType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." - } - }, - "mongodbDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/mongoDbType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." - } - }, - "gremlinDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/gremlinDatabaseType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." - } - }, - "cassandraKeyspaces": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraKeyspaceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "totalThroughputLimit": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of control plane Azure role-based access control assignments." - } - }, - "sqlRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleDefinitionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." - } - }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." - } - }, - "cassandraRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleDefinitionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." - } - }, - "cassandraRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings for the service." - } - }, - "capabilitiesToAdd": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "allowedValues": [ - "EnableCassandra", - "EnableTable", - "EnableGremlin", - "EnableMongo", - "DisableRateLimitingResponses", - "EnableServerless", - "EnableNoSQLVectorSearch", - "EnableNoSQLFullTextSearch", - "EnableMaterializedViews", - "DeleteAllItemsByPartitionKey" - ], - "metadata": { - "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." - } - }, - "backupPolicyType": { - "type": "string", - "defaultValue": "Continuous", - "allowedValues": [ - "Periodic", - "Continuous" - ], - "metadata": { - "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." - } - }, - "backupPolicyContinuousTier": { - "type": "string", - "defaultValue": "Continuous30Days", - "allowedValues": [ - "Continuous30Days", - "Continuous7Days" - ], - "metadata": { - "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." - } - }, - "backupIntervalInMinutes": { - "type": "int", - "defaultValue": 240, - "minValue": 60, - "maxValue": 1440, - "metadata": { - "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." - } - }, - "backupRetentionIntervalInHours": { - "type": "int", - "defaultValue": 8, - "minValue": 2, - "maxValue": 720, - "metadata": { - "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." - } - }, - "backupStorageRedundancy": { - "type": "string", - "defaultValue": "Local", - "allowedValues": [ - "Geo", - "Local", - "Zone" - ], - "metadata": { - "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." - } - }, - "networkRestrictions": { - "$ref": "#/definitions/networkRestrictionType", - "defaultValue": { - "ipRules": [], - "virtualNetworkRules": [], - "publicNetworkAccess": "Disabled" - }, - "metadata": { - "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "Tls12", - "allowedValues": [ - "Tls12" - ], - "metadata": { - "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." - } - }, - "enableBurstCapacity": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." - } - }, - "enableCassandraConnector": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." - } - }, - "enablePartitionMerge": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." - } - }, - "enablePerRegionPerPartitionAutoscale": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." - } - }, - "analyticalStorageConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" - }, - "description": "Optional. Analytical storage specific properties." - }, - "nullable": true - }, - "cors": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" - }, - "description": "Optional. The CORS policy for the Cosmos DB database account." - }, - "nullable": true - }, - "defaultIdentity": { - "$ref": "#/definitions/defaultIdentityType", - "defaultValue": { - "name": "FirstPartyIdentity" - }, - "metadata": { - "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInControlPlaneRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", - "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", - "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", - "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", - "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" - }, - "databaseAccount": { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", - "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", - "dependsOn": [ - "cMKKeyVault::cMKKey" - ] - }, - "databaseAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_diagnosticSettings": { - "copy": { - "name": "databaseAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_roleAssignments": { - "copy": { - "name": "databaseAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlDatabases": { - "copy": { - "name": "databaseAccount_sqlDatabases", - "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" - }, - "containers": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" - }, - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "3972888645334640168" + "databaseAccount_cassandraRoleDefinitions": { + "copy": { + "name": "databaseAccount_cassandraRoleDefinitions", + "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "roleName": { + "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "dataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" + }, + "notDataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "cassandraRoleAssignments": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10787709019875067397" + }, + "name": "DocumentDB Database Account Cassandra Role Definitions.", + "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." + }, + "definitions": { + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]", + "notDataActions": "[parameters('notDataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cassandra role definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cassandra role definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the cassandra role definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_cassandraKeyspaces", + "databaseAccount_cassandraRoleDefinitions" + ] + }, + "databaseAccount_mongodbDatabases": { + "copy": { + "name": "databaseAccount_mongodbDatabases", + "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "collections": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "autoscaleSettings": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "13897098552792121791" + }, + "name": "DocumentDB Database Account MongoDB Databases", + "description": "This module deploys a MongoDB Database within a CosmosDB Account." + }, + "definitions": { + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a collection." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "mongodbDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "mongodbDatabase_collections": { + "copy": { + "name": "mongodbDatabase_collections", + "count": "[length(coalesce(parameters('collections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "mongodbDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + }, + "indexes": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + }, + "shardKey": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "16151461445994734468" + }, + "name": "DocumentDB Database Account MongoDB Database Collections", + "description": "This module deploys a MongoDB Database Collection." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "mongodbDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]", + "indexes": "[parameters('indexes')]", + "shardKey": "[parameters('shardKey')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database collection." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database collection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "mongodbDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "name": "DocumentDB Database Account SQL Databases", - "description": "This module deploys a SQL Database in a CosmosDB Account." - }, - "definitions": { - "containerType": { - "type": "object", + "databaseAccount_gremlinDatabases": { + "copy": { + "name": "databaseAccount_gremlinDatabases", + "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", "properties": { - "name": { - "type": "string", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "graphs": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. Name of the container." + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11959636451300474346" + }, + "name": "DocumentDB Database Account Gremlin Databases", + "description": "This module deploys a Gremlin Database within a CosmosDB Account." + }, + "definitions": { + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a graph." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + } + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "gremlinDatabase_gremlinGraphs": { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(coalesce(parameters('graphs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "partitionKeyPaths": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10487122333182352122" + }, + "name": "DocumentDB Database Accounts Gremlin Databases Graphs", + "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount::gremlinDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinGraph": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": "[parameters('indexingPolicy')]", + "partitionKey": { + "paths": "[parameters('partitionKeyPaths')]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "gremlinDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_tables": { + "copy": { + "name": "databaseAccount_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" } }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1787500858429182824" + }, + "name": "Azure Cosmos DB account tables", + "description": "This module deploys a table within an Azure Cosmos DB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "table": { + "type": "Microsoft.DocumentDB/databaseAccounts/tables", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_cassandraKeyspaces": { + "copy": { + "name": "databaseAccount_cassandraKeyspaces", + "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "conflictResolutionPolicy": { - "type": "object", + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" + }, + "views": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15257396763463366586" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces", + "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." + }, + "definitions": { + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra table." + } + }, + "viewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra view (materialized view)." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/viewType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + "autoscaleSettingsMaxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { - "type": "array", - "items": { - "type": "string" + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + } }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + "cassandraKeyspace": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + "cassandraKeyspace_tables": { + "copy": { + "name": "cassandraKeyspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "schema": { + "value": "[parameters('tables')[copyIndex()].schema]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + }, + "throughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "defaultTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15998065591386988132" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Tables", + "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra table resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the Cassandra table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "defaultTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraTable": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "schema": "[parameters('schema')]", + "defaultTtl": "[parameters('defaultTtl')]", + "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + }, + "cassandraKeyspace_views": { + "copy": { + "name": "cassandraKeyspace_views", + "count": "[length(parameters('views'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('views')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "viewDefinition": { + "value": "[parameters('views')[copyIndex()].viewDefinition]" + }, + "throughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6617803098467821091" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Views", + "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra view." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags of the Cassandra view resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraView": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "viewDefinition": "[parameters('viewDefinition')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra view." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra view." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra view was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + } }, - "nullable": true - }, - "kind": { - "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra keyspace." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra keyspace." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra keyspace was created in." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a container." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, "dependsOn": [ "databaseAccount" ] }, - "container": { + "databaseAccount_privateEndpoints": { "copy": { - "name": "container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" + "name": "databaseAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, - "sqlDatabaseName": { - "value": "[parameters('name')]" + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" }, - "analyticalStorageTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, - "conflictResolutionPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, - "defaultTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "kind": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, - "version": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" }, - "paths": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" }, - "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", - "uniqueKeyPolicyKeys": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -53316,571 +56159,602 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "4781880351108045502" + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } }, - "name": "DocumentDB Database Account SQL Database Containers", - "description": "This module deploys a SQL Database Container in a CosmosDB Account." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "sqlDatabaseName": { + "subnetResourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "name": { - "type": "string", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. Name of the container." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "conflictResolutionPolicy": { - "type": "object", + "ipConfigurations": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." }, "nullable": true }, - "defaultTtl": { - "type": "int", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "nullable": true, - "minValue": -1, - "maxValue": 2147483647, "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, - "throughput": { - "type": "int", - "defaultValue": 400, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. Location for all Resources." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, - "maxValue": 1000000, "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" }, - "description": "Optional. Tags of the SQL Database resource." + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." }, "nullable": true }, - "paths": { + "customDnsConfigs": { "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" }, - "description": "Optional. Indexing policy of the container." + "description": "Optional. Custom DNS configurations." }, "nullable": true }, - "uniqueKeyPolicyKeys": { + "manualPrivateLinkServiceConnections": { "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." }, "nullable": true }, - "kind": { - "type": "string", - "defaultValue": "Hash", - "allowedValues": [ - "Hash", - "MultiHash" - ], + "privateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true }, - "version": { - "type": "int", - "defaultValue": 1, - "allowedValues": [ - 1, - 2 - ], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "variables": { "copy": [ { - "name": "partitionKeyPaths", - "count": "[length(parameters('paths'))]", - "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } - ] + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } }, "resources": { - "databaseAccount::sqlDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "container": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the container was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "sqlDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlRoleDefinitions": { - "copy": { - "name": "databaseAccount_sqlRoleDefinitions", - "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "dataActions": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" - }, - "roleName": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "sqlRoleAssignments": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "8514367433037227852" - }, - "name": "DocumentDB Database Account SQL Role Definitions.", - "description": "This module deploys a SQL Role Definision in a CosmosDB Account." - }, - "definitions": { - "sqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SQL Role Assignments." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the Role Definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of data actions that are allowed." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." - } - }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", - "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ - { - "dataActions": "[parameters('dataActions')]" - } - ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" - } - }, - "databaseAccount_sqlRoleAssignments": { - "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "roleDefinitionIdOrName": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } } }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" } } } - } - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" - } + }, + "dependsOn": [ + "privateEndpoint" + ] } }, "outputs": { - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the SQL Role Assignment." + "description": "The resource group the private endpoint was deployed into." }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the SQL Role Assignment." + "description": "The resource ID of the private endpoint." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." + "description": "The name of the private endpoint." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } }, "dependsOn": [ - "sqlRoleDefinition" + "databaseAccount" ] } }, @@ -53888,69 +56762,158 @@ "name": { "type": "string", "metadata": { - "description": "The name of the SQL Role Definition." + "description": "The name of the database account." }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the SQL Role Definition." + "description": "The resource ID of the database account." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." + "description": "The name of the resource group the database account was created in." }, "value": "[resourceGroup().name]" }, - "roleName": { + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" + }, + "endpoint": { "type": "string", "metadata": { - "description": "The role name of the SQL Role Definition." + "description": "The endpoint of the database account." + }, + "value": "[reference('databaseAccount').documentEndpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "primaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" + }, + "primaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" + }, + "primaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" + }, + "primaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" + }, + "secondaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" + }, + "secondaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" + }, + "secondaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" + }, + "secondaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only connection string." }, - "value": "[reference('sqlRoleDefinition').roleName]" + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" } } } }, "dependsOn": [ - "databaseAccount" + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", + "virtualNetwork" ] }, - "databaseAccount_sqlRoleAssignments": { - "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" - }, + "avmAiSearch": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "roleDefinitionIdOrName": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + "name": { + "value": "[format('srch-{0}', variables('solutionSuffix'))]" }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + "location": { + "value": "[parameters('location')]" }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + "skuName": { + "value": "basic" }, - "scope": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -53960,322 +56923,204 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + "version": "0.42.1.51946", + "templateHash": "8530209533589901450" + } }, "parameters": { - "databaseAccountName": { + "solutionName": { "type": "string", + "minLength": 3, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Solution name suffix used to derive the resource name." } }, "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." } }, - "roleDefinitionIdOrName": { + "location": { "type": "string", "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." + "description": "Azure region for the resource." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Tags to apply to the resource." } }, - "scope": { + "skuName": { "type": "string", - "nullable": true, + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + "description": "SKU name for the search service." } - } - }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." } }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" - } - } - }, - "outputs": { - "name": { - "type": "string", + "partitionCount": { + "type": "int", + "defaultValue": 1, "metadata": { - "description": "The name of the SQL Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + "description": "Number of partitions." + } }, - "resourceId": { + "hostingMode": { "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], "metadata": { - "description": "The resource ID of the SQL Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + "description": "Hosting mode." + } }, - "resourceGroupName": { + "semanticSearch": { "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_sqlDatabases", - "databaseAccount_sqlRoleDefinitions" - ] - }, - "databaseAccount_cassandraRoleDefinitions": { - "copy": { - "name": "databaseAccount_cassandraRoleDefinitions", - "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "roleName": { - "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "dataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" - }, - "notDataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "cassandraRoleAssignments": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10787709019875067397" - }, - "name": "DocumentDB Database Account Cassandra Role Definitions.", - "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." - }, - "definitions": { - "cassandraRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_export!": true + "description": "Semantic search tier." } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Whether to disable local authentication." } }, - "name": { + "managedIdentityType": { "type": "string", - "nullable": true, + "defaultValue": "SystemAssigned", "metadata": { - "description": "Optional. The unique identifier of the Role Definition." + "description": "Managed identity type for the search service." } }, - "roleName": { + "publicNetworkAccess": { "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + "description": "Public network access setting." } }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "notDataActions": { + "diagnosticSettings": { "type": "array", - "items": { - "type": "string" - }, "defaultValue": [], "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + "description": "Diagnostic settings for monitoring." } }, - "assignableScopes": { + "privateEndpoints": { "type": "array", - "items": { - "type": "string" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + "description": "Private endpoint configurations." } }, - "cassandraRoleAssignments": { + "roleAssignments": { "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + "description": "Optional. Array of role assignments to create on the AI Search service." } } }, "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", - "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ - { - "dataActions": "[parameters('dataActions')]", - "notDataActions": "[parameters('notDataActions')]" - } - ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" } }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, + "searchServiceUpdate": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('avm.res.search.update.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[parameters('name')]" }, - "roleDefinitionId": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + "location": { + "value": "[parameters('location')]" }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "sku": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + "managedIdentities": { + "value": { + "systemAssigned": "[equals(parameters('managedIdentityType'), 'SystemAssigned')]" + } }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" - } + "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -54284,605 +57129,2304 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" + "version": "0.39.26.7824", + "templateHash": "6207719545398489494" + }, + "name": "Search Services", + "description": "This module deploys a Search Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the API Admin keys generated by the modules." + } + }, + "primaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAdminKey secret name to create." + } + }, + "secondaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAdminKey secret name to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } + } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." } }, - "name": { + "authOptions": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/authOptions" + }, + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + }, + "nullable": true + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "computeType": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Confidential", + "Default" + ], + "metadata": { + "description": "Optional. The compute type of the search service." + } + }, + "cmkEnforcement": { "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "dataExfiltrationProtections": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, + "allowedValues": [ + "All" + ], "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + "description": "Optional. A list of data exfiltration scenarios that are explicitly disallowed for the search service. Currently, the only supported value is 'All' to disable all possible data export scenarios with more fine grained controls planned for the future." } }, - "principalId": { + "hostingMode": { "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." } }, - "roleDefinitionId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." + "description": "Optional. Location for all Resources." } }, - "scope": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings for all Resources in the solution." + } + }, + "networkRuleSet": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/networkRuleSet" + }, + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + }, + "nullable": true + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } + }, + "publicNetworkAccess": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", "nullable": true, "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to help categorize the resource in the Azure portal." + }, + "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', '')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + "authOptions": "[parameters('authOptions')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]", + "computeType": "[parameters('computeType')]", + "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra Role Assignment." + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + "dependsOn": [ + "searchService" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "2115224445601868607" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource." + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "cassandraRoleDefinition" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cassandra role definition." - }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cassandra role definition." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the cassandra role definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" - }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_cassandraKeyspaces", - "databaseAccount_cassandraRoleDefinitions" - ] - }, - "databaseAccount_mongodbDatabases": { - "copy": { - "name": "databaseAccount_mongodbDatabases", - "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "collections": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" - }, - "autoscaleSettings": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "13897098552792121791" - }, - "name": "DocumentDB Database Account MongoDB Databases", - "description": "This module deploys a MongoDB Database within a CosmosDB Account." - }, - "definitions": { - "collectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a collection." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "items": { - "$ref": "#/definitions/collectionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "autoscaleSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" - }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "mongodbDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "mongodbDatabase_collections": { - "copy": { - "name": "mongodbDatabase_collections", - "count": "[length(coalesce(parameters('collections'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "mongodbDatabaseName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" - }, - "indexes": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" - }, - "shardKey": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "16151461445994734468" + "dependsOn": [ + "searchService" + ] }, - "name": "DocumentDB Database Account MongoDB Database Collections", - "description": "This module deploys a MongoDB Database Collection." + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "696453183181258843" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } }, - "parameters": { - "databaseAccountName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." - } + "description": "The name of the search service." + }, + "value": "[parameters('name')]" }, - "mongodbDatabaseName": { + "resourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." - } + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. Name of the collection." - } + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" }, - "throughput": { - "type": "int", - "defaultValue": 400, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" }, - "indexes": { - "type": "array", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2025-05-01', 'full').location]" }, - "shardKey": { - "type": "object", + "endpoint": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", - "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]", - "indexes": "[parameters('indexes')]", - "shardKey": "[parameters('shardKey')]" + "description": "The endpoint of the search service." + }, + "value": "[reference('searchService').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" } } - } - ], - "outputs": { - "name": { - "type": "string", + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "The name of the mongodb database collection." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": "[parameters('name')]" + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "resourceId": { - "type": "string", + "primaryKey": { + "type": "securestring", "metadata": { - "description": "The resource ID of the mongodb database collection." + "description": "The primary admin API key of the search service." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" }, - "resourceGroupName": { - "type": "string", + "secondaryKey": { + "type": "securestring", "metadata": { - "description": "The name of the resource group the mongodb database collection was created in." + "description": "The secondaryKey admin API key of the search service." }, - "value": "[resourceGroup().name]" + "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" } } } }, "dependsOn": [ - "mongodbDatabase" + "searchService" ] } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the mongodb database." + "description": "Name of the AI Search service." }, "value": "[parameters('name')]" }, - "resourceId": { + "endpoint": { "type": "string", "metadata": { - "description": "The resource ID of the mongodb database." + "description": "Endpoint URL of the AI Search service." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" }, - "resourceGroupName": { + "identityPrincipalId": { "type": "string", "metadata": { - "description": "The name of the resource group the mongodb database was created in." + "description": "System-assigned identity principal ID." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" } } } - }, - "dependsOn": [ - "databaseAccount" - ] + } }, - "databaseAccount_gremlinDatabases": { - "copy": { - "name": "databaseAccount_gremlinDatabases", - "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" - }, + "avmAppConfig": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", + "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('location')]" + } + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } }, - "graphs": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + "sku": { + "value": "Standard" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "disableLocalAuth": { + "value": false + }, + "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + } + ] }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_PROCESS", + "value": "Processes" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMA", + "value": "Schemas" + }, + { + "name": "APP_COSMOS_DATABASE", + "value": "ContentProcess" + }, + { + "name": "APP_CPS_CONFIGURATION", + "value": "cps-configuration" + }, + { + "name": "APP_CPS_MAX_FILESIZE_MB", + "value": "20" + }, + { + "name": "APP_CPS_PROCESSES", + "value": "cps-processes" + }, + { + "name": "APP_MESSAGE_QUEUE_EXTRACT", + "value": "content-pipeline-extract-queue" + }, + { + "name": "APP_MESSAGE_QUEUE_INTERVAL", + "value": "5" + }, + { + "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", + "value": "180" + }, + { + "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", + "value": "10" + }, + { + "name": "APP_PROCESS_STEPS", + "value": "extract,map,evaluate,save" + }, + { + "name": "APP_STORAGE_BLOB_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" + }, + { + "name": "APP_STORAGE_QUEUE_URL", + "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" + }, + { + "name": "APP_COSMOS_CONNSTR", + "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", + "value": "claimprocesses" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCHES", + "value": "batches" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMASET", + "value": "Schemasets" + }, + { + "name": "APP_CPS_PROCESS_BATCH", + "value": "process-batch" + }, + { + "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", + "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" + }, + { + "name": "APP_CPS_POLL_INTERVAL_SECONDS", + "value": "3" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference('avmStorageAccount').outputs.name.value]" + }, + { + "name": "CLAIM_PROCESS_QUEUE_NAME", + "value": "claim-process-queue" + }, + { + "name": "DEAD_LETTER_QUEUE_NAME", + "value": "claim-process-dead-letter-queue" + }, + { + "name": "AZURE_OPENAI_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", + "value": "[parameters('gptModelName')]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_OPENAI_ENDPOINT_BASE", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", + "value": "" + }, + { + "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", + "value": "" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + }, + { + "name": "GLOBAL_LLM_SERVICE", + "value": "AzureOpenAI" + }, + { + "name": "GPT5_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "GPT5_CHAT_DEPLOYMENT_NAME", + "value": "gpt-5" + }, + { + "name": "GPT5_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + }, + { + "name": "PHI4_API_VERSION", + "value": "2024-05-01-preview" + }, + { + "name": "PHI4_CHAT_DEPLOYMENT_NAME", + "value": "phi-4" + }, + { + "name": "PHI4_ENDPOINT", + "value": "[reference('avmAiServices').outputs.endpoint.value]" + } + ] }, - "throughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + "publicNetworkAccess": { + "value": "Enabled" } }, "template": { @@ -54892,1212 +59436,722 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11959636451300474346" + "version": "0.37.4.10188", + "templateHash": "396653159019145335" }, - "name": "DocumentDB Database Account Gremlin Databases", - "description": "This module deploys a Gremlin Database within a CosmosDB Account." + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." }, "definitions": { - "graphType": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the graph." + "description": "The name of the private endpoint." } }, - "tags": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true + "description": "The resource ID of the private endpoint." + } }, - "indexingPolicy": { - "type": "object", + "groupId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true + "description": "The group Id for the private endpoint Group." + } }, - "partitionKeyPaths": { + "customDnsConfigs": { "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "nullable": true + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a graph." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." + "__bicep_export!": true } }, - "tags": { + "replicaLocationType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } }, - "description": "Optional. Tags of the Gremlin database resource." + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", "metadata": { - "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for a replica location" } }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" }, - "gremlinDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } } }, - "dependsOn": [ - "databaseAccount" - ] + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "gremlinDatabase_gremlinGraphs": { - "copy": { - "name": "gremlinDatabase_gremlinGraphs", - "count": "[length(coalesce(parameters('graphs'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "_1.privateEndpointIpConfigurationType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" - }, - "gremlinDatabaseName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" - }, - "partitionKeyPaths": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10487122333182352122" - }, - "name": "DocumentDB Database Accounts Gremlin Databases Graphs", - "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." - }, - "parameters": { - "name": { + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "Required. Name of the graph." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "databaseAccountName": { + "memberName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." } }, - "gremlinDatabaseName": { + "privateIPAddress": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true } }, - "resources": { - "databaseAccount::gremlinDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "gremlinGraph": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "indexingPolicy": "[parameters('indexingPolicy')]", - "partitionKey": { - "paths": "[parameters('partitionKeyPaths')]" - } + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." } } } }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the graph." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the graph." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the graph was created in." - }, - "value": "[resourceGroup().name]" - } + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } }, - "dependsOn": [ - "gremlinDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Gremlin database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Gremlin database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Gremlin database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_tables": { - "copy": { - "name": "databaseAccount_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1787500858429182824" - }, - "name": "Azure Cosmos DB account tables", - "description": "This module deploys a table within an Azure Cosmos DB Account." - }, - "parameters": { - "name": { - "type": "string", "metadata": { - "description": "Required. Name of the table." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "tags": { + "_1.roleAssignmentType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } }, - "description": "Optional. Tags for the table." + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" }, - "table": { - "type": "Microsoft.DocumentDB/databaseAccounts/tables", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "customerManagedKeyWithAutoRotateType": { + "type": "object", "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } } }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraKeyspaces": { - "copy": { - "name": "databaseAccount_cassandraKeyspaces", - "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "tables": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" - }, - "views": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15257396763463366586" + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "name": "DocumentDB Database Account Cassandra Keyspaces", - "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." - }, - "definitions": { - "tableType": { + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the table." + "description": "Optional. The name of the diagnostic setting." } }, - "schema": { - "type": "object", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the table." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the table." + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } }, - "defaultTtl": { - "type": "int", + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], "nullable": true, "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "analyticalStorageTtl": { - "type": "int", + "workspaceResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Analytical TTL for the table." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "throughput": { - "type": "int", + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra table." + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } }, - "viewType": { + "privateEndpointSingleServiceType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the view." + "description": "Optional. The name of the Private Endpoint." } }, - "viewDefinition": { + "location": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. View definition (CQL statement)." + "description": "Optional. The location to deploy the Private Endpoint to." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags for the view." - }, - "nullable": true - }, - "throughput": { - "type": "int", + "privateLinkServiceConnectionName": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "description": "Optional. The name of the private link connection to create." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "service": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra view (materialized view)." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra keyspace." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra keyspace resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." - } - }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/viewType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraKeyspace": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "cassandraKeyspace_tables": { - "copy": { - "name": "cassandraKeyspace_tables", - "count": "[length(parameters('tables'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('tables')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "schema": { - "value": "[parameters('tables')[copyIndex()].schema]" - }, - "analyticalStorageTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" - }, - "throughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "defaultTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "resourceGroupResourceId": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15998065591386988132" - }, - "name": "DocumentDB Database Account Cassandra Keyspaces Tables", - "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra table resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "cassandraKeyspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." - } - }, - "schema": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the Cassandra table." - } - }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." - } - }, - "defaultTtl": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." - } - } - }, - "resources": { - "databaseAccount::cassandraKeyspace": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraTable": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "schema": "[parameters('schema')]", - "defaultTtl": "[parameters('defaultTtl')]", - "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra table was created in." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." } - } - }, - "dependsOn": [ - "cassandraKeyspace" - ] - }, - "cassandraKeyspace_views": { - "copy": { - "name": "cassandraKeyspace_views", - "count": "[length(parameters('views'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('views')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "viewDefinition": { - "value": "[parameters('views')[copyIndex()].viewDefinition]" - }, - "throughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "isManualConnection": { + "type": "bool", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "6617803098467821091" - }, - "name": "DocumentDB Database Account Cassandra Keyspaces Views", - "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra view." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags of the Cassandra view resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "cassandraKeyspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." - } - }, - "viewDefinition": { - "type": "string", - "metadata": { - "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - } - }, - "resources": { - "databaseAccount::cassandraKeyspace": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-05-01-preview", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraView": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "viewDefinition": "[parameters('viewDefinition')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra view." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra view." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra view was created in." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. If Manual Private Link Connection is required." } - } - }, - "dependsOn": [ - "cassandraKeyspace" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra keyspace." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra keyspace." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra keyspace was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_privateEndpoints": { - "copy": { - "name": "databaseAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { + }, + "manualConnectionRequestMessage": { "type": "string", "nullable": true, + "maxLength": 140, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "privateDnsZoneGroupConfigs": { + "customDnsConfigs": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Custom DNS configurations." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." } }, - "kind": { + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", "nullable": true, "metadata": { "description": "Optional. Specify the type of lock." } }, - "notes": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. Array of role assignments to create." } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." } }, - "privateDnsZoneResourceId": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "description": "The type of a private DNS zone group configuration.", + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -56172,7 +60226,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } @@ -56181,54 +60235,113 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Azure App Configuration." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all Resources." } }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. The managed identity definition for this resource." } }, - "customNetworkInterfaceName": { + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { "type": "string", "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." } }, - "ipConfigurations": { + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { "type": "array", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, "nullable": true, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. All Replicas to create." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. The diagnostic settings of the service." } }, "lock": { @@ -56252,41 +60365,18 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. Tags of the resource." }, "nullable": true }, - "privateLinkServiceConnections": { - "type": "array", + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } }, "enableTelemetry": { "type": "bool", @@ -56294,6 +60384,16 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } } }, "variables": { @@ -56304,25 +60404,38 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -56338,55 +60451,112 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] }, - "privateEndpoint_lock": { + "configurationStore_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "configurationStore" ] }, - "privateEndpoint_roleAssignments": { + "configurationStore_diagnosticSettings": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -56397,28 +60567,284 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "configurationStore" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" }, - "privateEndpointName": { + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -56428,13 +60854,175 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { "privateDnsZoneGroupConfigType": { "type": "object", "properties": { @@ -56453,1897 +61041,2836 @@ } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } } }, "parameters": { - "privateEndpointName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "privateDnsZoneConfigs": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "type": "string" }, - "minLength": 1, - "maxLength": 5, + "nullable": true, "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "name": { + "customNetworkInterfaceName": { "type": "string", - "defaultValue": "default", + "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, "privateEndpoint": { - "existing": true, "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" } } - ] - } + } + }, + "dependsOn": [ + "privateEndpoint" + ] } }, "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the private endpoint." }, "value": "[parameters('name')]" }, - "resourceId": { + "location": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The location the resource was deployed into." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" }, - "resourceGroupName": { + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The group Id for the private endpoint Group." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } }, "dependsOn": [ - "privateEndpoint" + "configurationStore" ] } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." + "description": "The name of the app configuration." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "The resource ID of the app configuration." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The resource group the app configuration store was deployed into." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" }, - "customDnsConfigs": { - "type": "array", + "endpoint": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." + "description": "The endpoint of the app configuration." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[reference('configurationStore').endpoint]" }, - "networkInterfaceResourceIds": { + "privateEndpoints": { "type": "array", "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "$ref": "#/definitions/privateEndpointOutputType" }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The private endpoints of the app configuration." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } }, "dependsOn": [ - "databaseAccount" + "avmAiServices", + "avmContainerApp", + "avmContainerApp_API", + "avmContainerApp_Web", + "avmContainerApp_Workflow", + "avmCosmosDB", + "avmStorageAccount", + "logAnalyticsWorkspace" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the database account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the database account." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the database account was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the database account." - }, - "value": "[reference('databaseAccount').documentEndpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the database account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "primaryReadWriteKey": { - "type": "securestring", - "metadata": { - "description": "The primary read-write key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" - }, - "primaryReadOnlyKey": { - "type": "securestring", - "metadata": { - "description": "The primary read-only key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" - }, - "primaryReadWriteConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary read-write connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" - }, - "primaryReadOnlyConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary read-only connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" - }, - "secondaryReadWriteKey": { - "type": "securestring", - "metadata": { - "description": "The secondary read-write key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" - }, - "secondaryReadOnlyKey": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" - }, - "secondaryReadWriteConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary read-write connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" - }, - "secondaryReadOnlyConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" - } - } - } - }, - "dependsOn": [ - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", - "virtualNetwork" - ] - }, - "avmAppConfig": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('location')]" - } - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "sku": { - "value": "Standard" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "disableLocalAuth": { - "value": false - }, - "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - } - ] - }, - "keyValues": { - "value": [ - { - "name": "APP_AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_AZURE_OPENAI_MODEL", - "value": "[parameters('gptModelName')]" - }, - { - "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_COSMOS_CONTAINER_PROCESS", - "value": "Processes" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMA", - "value": "Schemas" - }, - { - "name": "APP_COSMOS_DATABASE", - "value": "ContentProcess" - }, - { - "name": "APP_CPS_CONFIGURATION", - "value": "cps-configuration" - }, - { - "name": "APP_CPS_MAX_FILESIZE_MB", - "value": "20" - }, - { - "name": "APP_CPS_PROCESSES", - "value": "cps-processes" - }, - { - "name": "APP_MESSAGE_QUEUE_EXTRACT", - "value": "content-pipeline-extract-queue" - }, - { - "name": "APP_MESSAGE_QUEUE_INTERVAL", - "value": "5" - }, - { - "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", - "value": "180" - }, - { - "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", - "value": "10" - }, - { - "name": "APP_PROCESS_STEPS", - "value": "extract,map,evaluate,save" - }, - { - "name": "APP_STORAGE_BLOB_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" - }, - { - "name": "APP_STORAGE_QUEUE_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" - }, - { - "name": "APP_AI_PROJECT_ENDPOINT", - "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" - }, - { - "name": "APP_COSMOS_CONNSTR", - "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", - "value": "claimprocesses" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCHES", - "value": "batches" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMASET", - "value": "Schemasets" - }, - { - "name": "APP_CPS_PROCESS_BATCH", - "value": "process-batch" - }, - { - "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", - "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" - }, - { - "name": "APP_CPS_POLL_INTERVAL_SECONDS", - "value": "3" - }, - { - "name": "APP_STORAGE_ACCOUNT_NAME", - "value": "[reference('avmStorageAccount').outputs.name.value]" - }, - { - "name": "CLAIM_PROCESS_QUEUE_NAME", - "value": "claim-process-queue" - }, - { - "name": "DEAD_LETTER_QUEUE_NAME", - "value": "claim-process-dead-letter-queue" - }, - { - "name": "AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", - "value": "[parameters('gptModelName')]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "AZURE_OPENAI_ENDPOINT_BASE", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", - "value": "" - }, - { - "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", - "value": "" - }, - { - "name": "AZURE_TRACING_ENABLED", - "value": "True" - }, - { - "name": "GLOBAL_LLM_SERVICE", - "value": "AzureOpenAI" - }, - { - "name": "GPT5_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "GPT5_CHAT_DEPLOYMENT_NAME", - "value": "gpt-5" - }, - { - "name": "GPT5_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "PHI4_API_VERSION", - "value": "2024-05-01-preview" - }, - { - "name": "PHI4_CHAT_DEPLOYMENT_NAME", - "value": "phi-4" - }, - { - "name": "PHI4_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - } - ] - }, - "publicNetworkAccess": { - "value": "Enabled" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } }, - "privateEndpointOutputType": { - "type": "object", + "avmAppConfig_update": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "privateEndpoints": { + "value": [ + { + "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", + "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "name": "appconfig-dns-zone-group", + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" + } + ] + }, + "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" + } + ] } }, - "groupId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "memberName": { - "type": "string", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "privateIPAddress": { - "type": "string", + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure App Configuration." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], - "metadata": { - "description": "Optional. Pricing tier of App Configuration." - } - }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], - "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "keyValues": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." - } - }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All Replicas to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, - "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" - }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the key." + "description": "Required. Name of the Azure App Configuration." } }, - "value": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], "metadata": { - "description": "Required. The value of the key-value." + "description": "Optional. Pricing tier of App Configuration." } }, - "appConfigurationName": { + "createMode": { "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." } }, - "contentType": { + "publicNetworkAccess": { "type": "string", "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", - "nullable": true, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "appConfiguration": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { "type": "Microsoft.AppConfiguration/configurationStores", "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" - } + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the key values." + "description": "The name of the app configuration." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the key values." + "description": "The resource ID of the app configuration." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the batch account was deployed into." + "description": "The resource group the app configuration store was deployed into." }, "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" - }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", - "metadata": { - "description": "Optional. Name of the replica." - } }, - "appConfigurationName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - } - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The resource group the app configuration was deployed into." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" }, - "name": { + "endpoint": { "type": "string", "metadata": { - "description": "The name of the replica that was deployed." + "description": "The endpoint of the app configuration." }, - "value": "[parameters('name')]" + "value": "[reference('configurationStore').endpoint]" }, - "resourceId": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "The resource ID of the replica that was deployed." + "description": "The private endpoints of the app configuration." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } }, "dependsOn": [ - "configurationStore" + "avmAppConfig", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", + "virtualNetwork" ] }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, + "avmContainerApp_update": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -58351,42 +63878,91 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "location": { + "value": "[parameters('location')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "value": "[parameters('enableTelemetry')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "workloadProfileName": { + "value": "Consumption" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "registries": { + "value": null }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "value": "[parameters('tags')]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "activeRevisionsMode": { + "value": "Single" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "ingressExternal": { + "value": false }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" + } } }, "template": { @@ -58396,143 +63972,636 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { + "scaleType": { "type": "object", "properties": { - "name": { - "type": "string", + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. The cooldown period in seconds." } }, - "privateDnsZoneGroupConfigs": { + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/scaleRuleType" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The scaling rules." } } }, "metadata": { - "__bicep_export!": true + "description": "The scale settings for the Container App." } }, - "ipConfigurationType": { + "scaleRuleType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. The name of the scaling rule." } }, - "properties": { + "custom": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." } } }, "metadata": { - "__bicep_export!": true + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." } }, - "privateLinkServiceConnectionType": { + "secretType": { "type": "object", "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. The name of the container app secret." } }, - "properties": { + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." }, + "nullable": true + }, + "httpSettings": { + "type": "object", "metadata": { - "description": "Required. Properties of private link service connection." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." } }, - "customDnsConfigType": { + "diagnosticSettingMetricsOnlyType": { "type": "object", "properties": { - "fqdn": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. The name of diagnostic setting." } }, - "ipAddresses": { + "metricCategories": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } }, + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, "lockType": { @@ -58556,35 +64625,47 @@ "metadata": { "description": "Optional. Specify the type of lock." } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "privateDnsZoneGroupConfigType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "privateDnsZoneResourceId": { - "type": "string", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -58659,7 +64740,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -58668,54 +64749,161 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Container App." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all Resources." } }, - "applicationSecurityGroupResourceIds": { + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/ingressPortMappingType" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. Settings to expose additional ports on container app." } }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } }, - "ipConfigurations": { + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { "type": "array", "items": { - "$ref": "#/definitions/ipConfigurationType" + "$ref": "#/definitions/serviceBindingType" }, "nullable": true, "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. List of container app services bound to the app." } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. Controls how active revisions are handled for the Container app." } }, - "location": { + "environmentResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Required. Resource ID of environment." } }, "lock": { @@ -58725,6 +64913,33 @@ "description": "Optional. The lock settings of the service." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "roleAssignments": { "type": "array", "items": { @@ -58735,48 +64950,162 @@ "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDnsConfigs": { + "customDomains": { "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Optional. The termination grace period for the container app." } }, - "manualPrivateLinkServiceConnections": { + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { "type": "array", "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "$ref": "#/definitions/secretType" }, "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. The secrets of the Container App." } }, - "privateLinkServiceConnections": { + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. Workload profile name to pin for container app execution." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, @@ -58788,25 +65117,24 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -58822,55 +65150,62 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", "name": "[parameters('name')]", - "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" } } }, - "privateEndpoint_lock": { + "containerApp_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_roleAssignments": { + "containerApp_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "containerApp_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -58881,28 +65216,75 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "containerAppName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" } }, "template": { @@ -58912,88 +65294,125 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." }, - "definitions": { - "privateDnsZoneGroupConfigType": { + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." }, + "nullable": true + }, + "globalValidation": { + "type": "object", "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." }, - "minLength": 1, - "maxLength": 5, + "nullable": true + }, + "login": { + "type": "object", "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "name": { - "type": "string", - "defaultValue": "default", + "platform": { + "type": "object", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" } } }, @@ -59001,21 +65420,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the set of Container App Auth configs." }, - "value": "[parameters('name')]" + "value": "current" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the set of Container App Auth configs." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The resource group containing the set of Container App Auth configs." }, "value": "[resourceGroup().name]" } @@ -59023,1572 +65442,1769 @@ } }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" + ] + }, + "avmContainerApp_API_update": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "registries": { + "value": null + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "description": "The type for a container app probe HTTP GET." + } }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "description": "The type for a container app probe HTTP GET header." + } }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } }, "metadata": { - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "description": "The type for a container app probe TCP socket." + } }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } }, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "description": "The scale settings for the Container App." + } }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the app configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the app configuration." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration store was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the app configuration." - }, - "value": "[reference('configurationStore').endpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the app configuration." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "avmAiServices", - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Web", - "avmContainerApp_Workflow", - "avmCosmosDB", - "avmStorageAccount", - "logAnalyticsWorkspace" - ] - }, - "avmAppConfig_update": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "publicNetworkAccess": { - "value": "Disabled" - }, - "privateEndpoints": { - "value": [ - { - "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", - "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", - "privateDnsZoneGroup": { - "privateDnsZoneGroupConfigs": [ - { - "name": "appconfig-dns-zone-group", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" - } - ] - }, - "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } - }, - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "The scaling rules for the Container App." } }, - "memberName": { - "type": "string", + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "The type for a volume mount." } }, - "privateIPAddress": { - "type": "string", + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "__bicep_export!": true, + "description": "The type for a secret." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure App Configuration." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], - "metadata": { - "description": "Optional. Pricing tier of App Configuration." - } - }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], - "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "keyValues": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." - } - }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All Replicas to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, - "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" - }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the key." + "description": "Required. Name of the Container App." } }, - "value": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The value of the key-value." + "description": "Optional. Location for all Resources." } }, - "appConfigurationName": { + "kind": { "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." } }, - "contentType": { + "clientCertificateMode": { "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", "nullable": true, "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "description": "Optional. Object userd to configure CORS policy." } }, - "tags": { + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Settings to expose additional ports on container app." } - } - }, - "resources": { - "appConfiguration": { - "existing": true, - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } - } - }, - "outputs": { - "name": { + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { "type": "string", "metadata": { - "description": "The name of the key values." + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." }, - "value": "[parameters('name')]" + "nullable": true }, - "resourceId": { + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", "metadata": { - "description": "The resource ID of the key values." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + "nullable": true }, - "resourceGroupName": { + "workloadProfileName": { "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, "metadata": { - "description": "The resource group the batch account was deployed into." + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, - "value": "[resourceGroup().name]" + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } }, - "parameters": { - "name": { + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", "metadata": { - "description": "Optional. Name of the replica." - } + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "appConfigurationName": { + "fqdn": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - } - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the app configuration was deployed into." + "description": "The name of the resource group the Container App was deployed into." }, "value": "[resourceGroup().name]" }, "name": { "type": "string", "metadata": { - "description": "The name of the replica that was deployed." + "description": "The name of the Container App." }, "value": "[parameters('name')]" }, - "resourceId": { + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { "type": "string", "metadata": { - "description": "The resource ID of the replica that was deployed." + "description": "The location the resource was deployed into." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } }, "dependsOn": [ - "configurationStore" + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader", + "cognitiveServicePrivateEndpoint" ] }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, + "avmContainerApp_Workflow_update": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -60596,42 +67212,90 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "location": { + "value": "[parameters('location')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "value": "[parameters('enableTelemetry')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "environmentResourceId": { + "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "workloadProfileName": { + "value": "Consumption" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "registries": { + "value": null }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + ] + } + }, + "containers": { + "value": [ + { + "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[reference('avmAppConfig').outputs.endpoint.value]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "activeRevisionsMode": { + "value": "Single" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "ingressExternal": { + "value": false }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "disableIngress": { + "value": true }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "scaleSettings": { + "value": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } } }, "template": { @@ -60641,143 +67305,636 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Container Apps", + "description": "This module deploys a Container App." }, "definitions": { - "privateDnsZoneGroupType": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { "type": "object", "properties": { "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." } }, - "privateDnsZoneGroupConfigs": { + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "type": "string" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type for a CORS policy." } }, - "ipConfigurationType": { + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. Name of the header." } }, - "properties": { + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { + }, + "workspaceResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. Properties of private link service connection." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { + }, + "eventHubAuthorizationRuleResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, + "eventHubName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, "lockType": { @@ -60801,35 +67958,47 @@ "metadata": { "description": "Optional. Specify the type of lock." } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "privateDnsZoneGroupConfigType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "privateDnsZoneResourceId": { - "type": "string", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -60904,7 +68073,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -60913,54 +68082,161 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Container App." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all Resources." } }, - "applicationSecurityGroupResourceIds": { + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/ingressPortMappingType" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. Settings to expose additional ports on container app." } }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } }, - "ipConfigurations": { + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { "type": "array", "items": { - "$ref": "#/definitions/ipConfigurationType" + "$ref": "#/definitions/serviceBindingType" }, "nullable": true, "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. List of container app services bound to the app." } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. Controls how active revisions are handled for the Container app." } }, - "location": { + "environmentResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Required. Resource ID of environment." } }, "lock": { @@ -60970,6 +68246,33 @@ "description": "Optional. The lock settings of the service." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "roleAssignments": { "type": "array", "items": { @@ -60980,48 +68283,162 @@ "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDnsConfigs": { + "customDomains": { "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Optional. The termination grace period for the container app." } }, - "manualPrivateLinkServiceConnections": { + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { "type": "array", "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "$ref": "#/definitions/secretType" }, "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. The secrets of the Container App." } }, - "privateLinkServiceConnections": { + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. Workload profile name to pin for container app execution." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, @@ -61033,25 +68450,24 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -61067,55 +68483,62 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", "name": "[parameters('name')]", - "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" } } }, - "privateEndpoint_lock": { + "containerApp_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_roleAssignments": { + "containerApp_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "containerApp_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -61126,28 +68549,75 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "containerAppName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" } }, "template": { @@ -61157,88 +68627,125 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." }, - "definitions": { - "privateDnsZoneGroupConfigType": { + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." }, + "nullable": true + }, + "httpSettings": { + "type": "object", "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." }, - "minLength": 1, - "maxLength": 5, + "nullable": true + }, + "platform": { + "type": "object", "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true }, - "name": { - "type": "string", - "defaultValue": "default", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" } } }, @@ -61246,21 +68753,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the set of Container App Auth configs." }, - "value": "[parameters('name')]" + "value": "current" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the set of Container App Auth configs." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The resource group containing the set of Container App Auth configs." }, "value": "[resourceGroup().name]" } @@ -61268,4898 +68775,3347 @@ } }, "dependsOn": [ - "privateEndpoint" + "containerApp" ] } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "The resource ID of the Container App." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The configuration of ingress fqdn." }, - "value": "[parameters('name')]" + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "location": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The name of the resource group the Container App was deployed into." }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "value": "[resourceGroup().name]" }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, + "name": { + "type": "string", "metadata": { - "description": "The custom DNS configurations of the private endpoint." + "description": "The name of the Container App." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[parameters('name')]" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The principal ID of the system assigned identity." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" }, - "groupId": { + "location": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The location the resource was deployed into." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } }, "dependsOn": [ - "configurationStore" + "applicationInsights", + "avmAppConfig", + "avmContainerAppEnv", + "avmContainerRegistryReader" ] } }, "outputs": { - "name": { + "CONTAINER_WEB_APP_NAME": { "type": "string", "metadata": { - "description": "The name of the app configuration." + "description": "The name of the Container App used for Web App." }, - "value": "[parameters('name')]" + "value": "[reference('avmContainerApp_Web').outputs.name.value]" }, - "resourceId": { + "CONTAINER_API_APP_NAME": { "type": "string", "metadata": { - "description": "The resource ID of the app configuration." + "description": "The name of the Container App used for API." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + "value": "[reference('avmContainerApp_API').outputs.name.value]" }, - "resourceGroupName": { + "CONTAINER_WEB_APP_FQDN": { "type": "string", "metadata": { - "description": "The resource group the app configuration store was deployed into." + "description": "The FQDN of the Container App." }, - "value": "[resourceGroup().name]" + "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" }, - "systemAssignedMIPrincipalId": { + "CONTAINER_API_APP_FQDN": { "type": "string", - "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "The FQDN of the Container App API." }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" }, - "location": { + "CONTAINER_APP_NAME": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The name of the Container App used for APP." }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" + "value": "[reference('avmContainerApp').outputs.name.value]" }, - "endpoint": { + "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", "metadata": { - "description": "The endpoint of the app configuration." + "description": "The name of the Container App used for Workflow." }, - "value": "[reference('configurationStore').endpoint]" + "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "metadata": { + "description": "The user identity resource ID used fot the Container APP." }, + "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", "metadata": { - "description": "The private endpoints of the app configuration." + "description": "The user identity Principal ID used fot the Container APP." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } + "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "metadata": { + "description": "The name of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "metadata": { + "description": "The login server of the Azure Container Registry." + }, + "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "metadata": { + "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." + }, + "value": "[reference('avmAiServices').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "metadata": { + "description": "The resource group the resources were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "SOLUTION_NAME": { + "type": "string", + "metadata": { + "description": "The solution name." + }, + "value": "[parameters('solutionName')]" } } } - }, - "dependsOn": [ - "avmAppConfig", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", - "virtualNetwork" - ] + } }, - "avmContainerApp_update": { + { + "condition": "[variables('isBicep')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.bicep.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" + "solutionName": { + "value": "[parameters('solutionName')]" }, "location": { "value": "[parameters('location')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "azureAiServiceLocation": { + "value": "[parameters('azureAiServiceLocation')]" }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + "gptModelName": { + "value": "[parameters('gptModelName')]" }, - "workloadProfileName": { - "value": "Consumption" + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" }, - "registries": { - "value": null + "imageTag": { + "value": "[parameters('imageTag')]" }, - "tags": { - "value": "[parameters('tags')]" + "enablePrivateNetworking": { + "value": "[variables('effectiveEnablePrivateNetworking')]" }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } + "enableMonitoring": { + "value": "[variables('effectiveEnableMonitoring')]" }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } - ] + "enableRedundancy": { + "value": "[variables('effectiveEnableRedundancy')]" }, - "activeRevisionsMode": { - "value": "Single" + "enableScalability": { + "value": "[variables('effectiveEnableScalability')]" }, - "ingressExternal": { - "value": false + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "disableIngress": { - "value": true + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" - } + "tags": { + "value": "[parameters('tags')]" } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6422306545253132015" + }, + "name": "Content Processing Solution Accelerator - Bicep", + "description": "Deploys Content Processing resources using the restored private-repo module interfaces." }, "parameters": { - "name": { + "solutionName": { "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } + "defaultValue": "cps", + "minLength": 3, + "maxLength": 20 }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "azd": { + "type": "location" + } } }, - "kind": { + "azureAiServiceLocation": { "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + "azd": { + "type": "location" + } } }, - "clientCertificateMode": { + "gptModelName": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } + "defaultValue": "gpt-5.1" }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { + "containerRegistryEndpoint": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } + "defaultValue": "" }, - "ingressTransport": { + "imageTag": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } + "defaultValue": "latest_v2" }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false }, - "includeAddOns": { + "enableMonitoring": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } + "defaultValue": false }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } + "enableRedundancy": { + "type": "bool", + "defaultValue": false }, - "ingressAllowInsecure": { + "enableScalability": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } + "defaultValue": false }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } + "enableTelemetry": { + "type": "bool", + "defaultValue": true + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", + "tags": { + "type": "object", "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" + } + }, + "variables": { + "uniqueToken": "[substring(uniqueString(subscription().subscriptionId, resourceGroup().id, parameters('solutionName')), 0, 5)]", + "solutionSuffix": "[toLower(replace(replace(replace(format('{0}{1}', parameters('solutionName'), variables('uniqueToken')), '-', ''), '_', ''), '.', ''))]", + "managedIdentityName": "[format('id-{0}', variables('solutionSuffix'))]", + "containerRegistryName": "[replace(format('cr{0}', variables('solutionSuffix')), '-', '')]", + "storageAccountName": "[take(replace(format('st{0}', variables('solutionSuffix')), '-', ''), 24)]", + "cosmosDbName": "[format('cosmos-{0}', variables('solutionSuffix'))]", + "cosmosDatabaseName": "contentprocessing", + "cosmosContainerName": "documents", + "aiServicesName": "[format('aif-{0}', variables('solutionSuffix'))]", + "aiProjectName": "[format('proj-{0}', variables('solutionSuffix'))]", + "aiSearchName": "[format('srch-{0}', variables('solutionSuffix'))]", + "appConfigurationName": "[format('appcs-{0}', variables('solutionSuffix'))]", + "containerAppEnvironmentName": "[format('cae-{0}', variables('solutionSuffix'))]", + "contentProcessorAppName": "[format('ca-{0}-app', variables('solutionSuffix'))]", + "contentProcessorApiName": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "contentProcessorWebName": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "contentProcessorWorkflowName": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "modelDeploymentName": "[format('gpt-{0}', variables('solutionSuffix'))]", + "storageContainerName": "content", + "storageQueueName": "content", + "acrPullRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "storageBlobDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "storageQueueDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "appConfigurationDataReaderRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "cognitiveServicesOpenAiUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "cognitiveServicesUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "azureAiDeveloperRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "cosmosDbEndpoint": "[format('https://{0}.mongo.cosmos.azure.com:443/', variables('cosmosDbName'))]", + "apiProbes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 } + ] + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]" }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } + { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', variables('storageQueueName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageAccountName'), 'default')]" + ] }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." + { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2023-04-15", + "name": "[variables('cosmosDbName')]", + "location": "[parameters('location')]", + "kind": "MongoDB", + "tags": "[parameters('tags')]", + "properties": { + "databaseAccountOfferType": "Standard", + "locations": [ + { + "locationName": "[parameters('location')]", + "failoverPriority": 0, + "isZoneRedundant": "[parameters('enableRedundancy')]" + } + ], + "capabilities": [ + { + "name": "EnableMongo" + } + ], + "apiProperties": { + "serverVersion": "7.0" + }, + "disableLocalAuth": false, + "enableAutomaticFailover": false, + "enableMultipleWriteLocations": false, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]" } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}', variables('cosmosDbName'), variables('cosmosDatabaseName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosDatabaseName')]" }, - "description": "Optional. Tags of the resource." + "options": {} }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]" + ] }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2023-04-15", + "name": "[format('{0}/{1}/{2}', variables('cosmosDbName'), variables('cosmosDatabaseName'), variables('cosmosContainerName'))]", + "properties": { + "resource": { + "id": "[variables('cosmosContainerName')]", + "shardKey": { + "id": "Hash" + }, + "indexes": [ + { + "key": { + "keys": [ + "_id" + ] + } + } + ] }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + "options": {} }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', variables('cosmosDbName'), variables('cosmosDatabaseName'))]" + ] }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + { + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', variables('aiServicesName'), variables('aiProjectName'))]", + "location": "[parameters('azureAiServiceLocation')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "tags": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]", + "properties": {} }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', variables('containerRegistryName'))]", + "name": "[guid(variables('containerRegistryName'), variables('managedIdentityName'), 'acr-pull')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('acrPullRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'blob')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", + "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'queue')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorAppName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorApiName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" + ] }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWebName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64))]" + ] }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", + "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWorkflowName'), 'appconfig')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'openai-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" }, - "nullable": true + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'ai-developer')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" + ] }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", + "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'cog-user')]", + "properties": { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7692694992043508018" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "metadata": { + "description": "SKU name for the workspace." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "retentionInDays": "[parameters('retentionInDays')]", + "sku": { + "name": "[parameters('skuName')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01', 'full').location]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), '2023-09-01').customerId]" + } + } + } } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + { + "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "workspaceResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4667471246975862151" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('appi-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace to link to." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Application type." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable IP masking for security." + } + }, + "flowType": { + "type": "string", + "defaultValue": "Bluefield", + "metadata": { + "description": "Flow type for Application Insights." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "web", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "Flow_Type": "[parameters('flowType')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "publicNetworkAccessForIngestion": "Enabled", + "publicNetworkAccessForQuery": "Enabled" + } + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Application Insights instance." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Application Insights instance." + }, + "value": "[parameters('name')]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Instrumentation key for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Connection string for the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').ConnectionString]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "Application ID of the Application Insights instance." + }, + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('name')), '2020-02-02').AppId]" } } } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "identityName": { + "value": "[variables('managedIdentityName')]" }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "location": { + "value": "[parameters('location')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "14165903959794426055" + } }, "parameters": { - "containerAppName": { + "solutionName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Solution name used for resource naming." } }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Name of the managed identity." + } }, - "login": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "platform": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Tags to apply to the resource." } } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" } - }, + ], "outputs": { - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "Resource ID of the managed identity." }, - "value": "current" + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]" }, - "resourceId": { + "principalId": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Principal ID (object ID) of the managed identity." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').principalId]" }, - "resourceGroupName": { + "clientId": { "type": "string", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "Client ID of the managed identity." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" - ] - }, - "avmContainerApp_API_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 - } - ] - } - ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').clientId]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[parameters('identityName')]" } } } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." } }, - "corsPolicyType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" + "name": { + "value": "[variables('containerRegistryName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." + "sku": "[if(parameters('enableRedundancy'), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" } }, - "pollingInterval": { - "type": "int", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17432455227529690473" + } }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "adminUserEnabled": "[parameters('adminUserEnabled')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "dataEndpointEnabled": false, + "networkRuleBypassOptions": "AzureServices", + "policies": { + "exportPolicy": { + "status": "[parameters('exportPolicyStatus')]" + }, + "retentionPolicy": { + "status": "enabled", + "days": 7 + }, + "trustPolicy": { + "status": "disabled", + "type": "Notary" + } + }, + "zoneRedundancy": "Disabled" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + } } } - }, - "metadata": { - "description": "The type for a volume mount." } }, - "secretType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": "[if(parameters('enableRedundancy'), createObject('value', 'Standard_ZRS'), createObject('value', 'Standard_LRS'))]", + "containers": { + "value": [ + { + "name": "[variables('storageContainerName')]", + "publicAccess": "None" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" } }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17696053432794478605" + } }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "name": { + "type": "string", + "defaultValue": "[take(format('st{0}', toLower(replace(parameters('solutionName'), '-', ''))), 24)]", + "metadata": { + "description": "Name of the storage account." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "skuName": { + "type": "string", + "defaultValue": "Standard_LRS", + "metadata": { + "description": "Storage account SKU." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "metadata": { + "description": "Storage account kind." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Hot", + "Cool" + ], + "metadata": { + "description": "Access tier." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Allow blob public access." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Allow shared key access." + } + }, + "containers": { + "type": "array", + "defaultValue": [ + { + "name": "default", + "publicAccess": "None" } + ], + "metadata": { + "description": "Blob containers to create." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "properties": { + "accessTier": "[parameters('accessTier')]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "minimumTlsVersion": "TLS1_2", + "supportsHttpsTrafficOnly": true, + "encryption": { + "services": { + "blob": { + "enabled": true + }, + "file": { + "enabled": true + } + }, + "keySource": "Microsoft.Storage", + "requireInfrastructureEncryption": true } } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "blobContainers", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', parameters('containers')[copyIndex()].name)]", + "properties": { + "publicAccess": "[parameters('containers')[copyIndex()].publicAccess]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('name'), 'default')]" + ] } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Storage Account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Storage Account." + }, + "value": "[parameters('name')]" + }, + "blobEndpoint": { + "type": "string", + "metadata": { + "description": "Primary blob endpoint." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.blob]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } }, - "managedIdentityAllType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)]", "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('aiServicesName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "principalIds": { + "value": [] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7594344478012985364" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services account." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Required. Azure region for the resource." + } + }, + "principalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether public network access is allowed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to apply to the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "sku": { + "name": "S0" + }, + "properties": { + "customSubDomainName": "[parameters('name')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "disableLocalAuth": true, + "allowProjectManagement": true, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" + } + } + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principalIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", + "properties": { + "principalId": "[parameters('principalIds')[copyIndex()]]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AI Services account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the AI Services account." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the AI Services account." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01').endpoint]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01', 'full').identity.principalId]" + } + } + } } }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-model.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + "mode": "Incremental", + "parameters": { + "aiServicesAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "deploymentName": { + "value": "[variables('modelDeploymentName')]" + }, + "modelName": { + "value": "[parameters('gptModelName')]" + }, + "skuName": { + "value": "GlobalStandard" + }, + "skuCapacity": { + "value": 10 + } }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18411757618261752815" + } + }, + "parameters": { + "aiServicesAccountName": { + "type": "string", + "metadata": { + "description": "Required. Name of the parent AI Services account." + } + }, + "deploymentName": { + "type": "string", + "metadata": { + "description": "Required. Name for this model deployment." + } + }, + "modelFormat": { + "type": "string", + "defaultValue": "OpenAI", + "metadata": { + "description": "Optional. Model format (e.g., OpenAI)." + } + }, + "modelName": { + "type": "string", + "metadata": { + "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." + } + }, + "modelVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Model version. Empty string means latest." + } + }, + "raiPolicyName": { + "type": "string", + "defaultValue": "Microsoft.Default", + "metadata": { + "description": "Optional. RAI policy name." + } + }, + "skuName": { + "type": "string", + "metadata": { + "description": "Required. SKU name (e.g., Standard, GlobalStandard)." + } + }, + "skuCapacity": { + "type": "int", + "metadata": { + "description": "Required. SKU capacity (tokens per minute in thousands)." + } + } + }, + "resources": [ + { + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", + "properties": { + "model": { + "format": "[parameters('modelFormat')]", + "name": "[parameters('modelName')]", + "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" + }, + "raiPolicyName": "[parameters('raiPolicyName')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacity": "[parameters('skuCapacity')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the deployed model." + }, + "value": "[parameters('deploymentName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the model deployment." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]" + ] }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('aiSearchName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "tags": { + "value": "[parameters('tags')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "714050788324647491" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "searchServiceUpdate", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "managedIdentityType": { + "value": "[parameters('managedIdentityType')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3683977219901178221" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the existing AI Search service." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The Azure region of the search service." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "basic", + "metadata": { + "description": "SKU name for the search service." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of replicas." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Number of partitions." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Hosting mode." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "metadata": { + "description": "Semantic search tier." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether to disable local authentication." + } + }, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "metadata": { + "description": "Managed identity type for the search service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + } + }, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": { + "type": "[parameters('managedIdentityType')]" + }, + "properties": { + "replicaCount": "[parameters('replicaCount')]", + "partitionCount": "[parameters('partitionCount')]", + "hostingMode": "[parameters('hostingMode')]", + "semanticSearch": "[parameters('semanticSearch')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + } + } + ], + "outputs": { + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the AI Search system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.Search/searchServices', parameters('name')), '2025-05-01', 'full').identity.principalId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + ] + } + ], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." + }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'searchServiceUpdate'), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]" } } } } }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" + "expressionEvaluationOptions": { + "scope": "inner" }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[variables('containerAppEnvironmentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17265155980354931238" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the Container Apps Environment." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + } + }, + "infrastructureSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for VNet integration (optional)." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable zone redundancy." + } + } + }, + "resources": [ + { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "appLogsConfiguration": { + "destination": "log-analytics", + "logAnalyticsConfiguration": { + "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", + "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" + } + }, + "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", + "zoneRedundant": "[parameters('zoneRedundant')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container Apps Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container Apps Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The default domain of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The static IP address of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.app-config.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "name": { + "value": "[variables('appConfigurationName')]" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "location": { + "value": "[parameters('location')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName')), '2025-12-01').endpoints['AI Foundry API']]" + }, + { + "name": "APP_COSMOS_DB_ENDPOINT", + "value": "[variables('cosmosDbEndpoint')]" + }, + { + "name": "APP_COSMOS_DB_NAME", + "value": "[variables('cosmosDatabaseName')]" + }, + { + "name": "APP_COSMOS_DB_CONTAINER", + "value": "[variables('cosmosContainerName')]" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "APP_STORAGE_BLOB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.blobEndpoint.value]" + }, + { + "name": "APP_STORAGE_QUEUE_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_STORAGE_CONTAINER_NAME", + "value": "[variables('storageContainerName')]" + }, + { + "name": "APP_AI_SEARCH_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_SEARCH_INDEX", + "value": "content-index" + }, + { + "name": "APP_WORKFLOW_APP_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "APP_API_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + } + ] }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "18286182317157861590" + } }, "parameters": { - "containerAppName": { + "solutionName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Solution name used for naming convention." } }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", + "name": { + "type": "string", + "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Name of the App Configuration store." + } }, - "identityProviders": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "login": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "platform": { - "type": "object", + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Standard" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "SKU for the configuration store." + } }, - "enableTelemetry": { + "disableLocalAuth": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Disable local (key-based) authentication." + } + }, + "keyValues": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Key-value pairs to store in the configuration." } } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2023-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "Enabled" } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + { + "copy": { + "name": "configurationKeyValues", + "count": "[length(parameters('keyValues'))]" + }, + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } + "value": "[parameters('keyValues')[copyIndex()].value]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + ] } - }, + ], "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "The name of the App Configuration store." }, - "value": "current" + "value": "[parameters('name')]" }, - "resourceId": { + "endpoint": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "The endpoint of the App Configuration store." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "The resource ID of the App Configuration store." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" } } } }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]" ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" - ] - }, - "avmContainerApp_Workflow_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-app.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorAppName')]" }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" + "location": { + "value": "[parameters('location')]" }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" + "disableIngress": { + "value": true }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" + "containers": { + "value": [ + { + "name": "[variables('contentProcessorAppName')]", + "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" + } + ] }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + "scaleSettings": { + "value": { + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]" + } }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." + "tags": { + "value": "[parameters('tags')]" } }, - "pollingInterval": { - "type": "int", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] }, - "managedIdentityAllType": { - "type": "object", + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.content-api.{0}', variables('solutionSuffix')), 64)]", "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorApiName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorApiName')]", + "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", + "probes": "[variables('apiProbes')]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + ] }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('module.content-web.{0}', variables('solutionSuffix')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('contentProcessorWebName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWebName')]", + "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" + } + ] + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "corsPolicy": { + "value": { + "allowedOrigins": [ + "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "*" + ] + } + }, + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7554792250803110495" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Container Apps Environment." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Managed identity configuration." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 + }, + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Workload profile name." + } + } + }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", + "properties": { + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, + "template": { + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" + } + } + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the container app." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container app." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the container app." + }, + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" } } } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[variables('contentProcessorWorkflowName')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "ingressExternal": { + "value": true }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "ingressTargetPort": { + "value": 80 + }, + "containers": { + "value": [ + { + "name": "[variables('contentProcessorWorkflowName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "resources": { + "cpu": 2, + "memory": "4Gi" + }, + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" + } + ] }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "registries": { + "value": [ + { + "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", + "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "scaleSettings": { + "value": { + "minReplicas": 0, + "maxReplicas": 10 + } }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -66170,296 +72126,322 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "7554792250803110495" + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Name of the container app." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for deployment." + } }, - "globalValidation": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Resource tags." + } }, - "httpSettings": { - "type": "object", + "environmentResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Resource ID of the Container Apps Environment." + } }, - "identityProviders": { - "type": "object", + "containers": { + "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Container definitions." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable external ingress." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Target port for ingress." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Ingress transport protocol." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to allow insecure ingress connections." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable ingress entirely (for background workers)." + } + }, + "registries": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Container registry configurations." + } + }, + "secrets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Secret definitions." + } }, - "login": { + "managedIdentities": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Managed identity configuration." + } }, - "platform": { + "corsPolicy": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "CORS policy configuration." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Single", + "Multiple" + ], + "metadata": { + "description": "Active revision mode." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 0 }, - "nullable": true + "metadata": { + "description": "Scale settings (maxReplicas, minReplicas, rules)." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "workloadProfileName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Workload profile name." } } }, + "variables": { + "identityConfig": "[if(empty(parameters('managedIdentities')), createObject('type', 'None'), createObject('type', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), if(and(contains(parameters('managedIdentities'), 'systemAssigned'), parameters('managedIdentities').systemAssigned), 'SystemAssigned,UserAssigned', 'UserAssigned'), 'SystemAssigned'), 'userAssignedIdentities', if(contains(parameters('managedIdentities'), 'userAssignedResourceIds'), reduce(parameters('managedIdentities').userAssignedResourceIds, createObject(), lambda('cur', 'id', union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('id')), createObject())))), null())))]", + "ingressConfig": "[if(parameters('disableIngress'), null(), createObject('external', parameters('ingressExternal'), 'targetPort', parameters('ingressTargetPort'), 'transport', parameters('ingressTransport'), 'allowInsecure', parameters('ingressAllowInsecure'), 'corsPolicy', if(not(empty(parameters('corsPolicy'))), parameters('corsPolicy'), null())))]" + }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identityConfig')]", "properties": { - "mode": "Incremental", + "managedEnvironmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "ingress": "[variables('ingressConfig')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]" + }, "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "containers": "[parameters('containers')]", + "scale": { + "minReplicas": "[parameters('scaleSettings').minReplicas]", + "maxReplicas": "[parameters('scaleSettings').maxReplicas]", + "rules": "[if(contains(parameters('scaleSettings'), 'rules'), parameters('scaleSettings').rules, null())]" } } } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "The name of the container app." }, - "value": "current" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "The resource ID of the container app." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "resourceGroupName": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "The FQDN of the container app." }, - "value": "[resourceGroup().name]" + "value": "[if(not(parameters('disableIngress')), reference('containerApp').configuration.ingress.fqdn, '')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[if(contains(reference('containerApp', '2024-10-02-preview', 'full').identity.type, 'SystemAssigned'), reference('containerApp', '2024-10-02-preview', 'full').identity.principalId, '')]" } } } }, "dependsOn": [ - "containerApp" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" ] } - }, + ], "outputs": { - "resourceId": { + "SOLUTION_NAME": { "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + "value": "[parameters('solutionName')]" }, - "fqdn": { + "CONTAINER_WEB_APP_NAME": { "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, - "resourceGroupName": { + "CONTAINER_API_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, - "name": { + "CONTAINER_WEB_APP_FQDN": { "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" + "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, - "systemAssignedMIPrincipalId": { + "CONTAINER_API_APP_FQDN": { "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, - "location": { + "CONTAINER_APP_NAME": { "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_WORKFLOW_APP_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_APP_USER_IDENTITY_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "CONTAINER_APP_USER_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "CONTAINER_REGISTRY_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "CONTAINER_REGISTRY_LOGIN_SERVER": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[resourceGroup().name]" } } } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] + } } - }, + ], "outputs": { + "SOLUTION_NAME": { + "type": "string", + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.SOLUTION_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.SOLUTION_NAME.value)]" + }, "CONTAINER_WEB_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for Web App." - }, - "value": "[reference('avmContainerApp_Web').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_NAME.value)]" }, "CONTAINER_API_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for API." - }, - "value": "[reference('avmContainerApp_API').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_NAME.value)]" }, "CONTAINER_WEB_APP_FQDN": { "type": "string", - "metadata": { - "description": "The FQDN of the Container App." - }, - "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_FQDN.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_FQDN.value)]" }, "CONTAINER_API_APP_FQDN": { "type": "string", - "metadata": { - "description": "The FQDN of the Container App API." - }, - "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_FQDN.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_FQDN.value)]" }, "CONTAINER_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for APP." - }, - "value": "[reference('avmContainerApp').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_NAME.value)]" }, "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", - "metadata": { - "description": "The name of the Container App used for Workflow." - }, - "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WORKFLOW_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WORKFLOW_APP_NAME.value)]" }, "CONTAINER_APP_USER_IDENTITY_ID": { "type": "string", - "metadata": { - "description": "The user identity resource ID used fot the Container APP." - }, - "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_IDENTITY_ID.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_IDENTITY_ID.value)]" }, "CONTAINER_APP_USER_PRINCIPAL_ID": { "type": "string", - "metadata": { - "description": "The user identity Principal ID used fot the Container APP." - }, - "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value)]" }, "CONTAINER_REGISTRY_NAME": { "type": "string", - "metadata": { - "description": "The name of the Azure Container Registry." - }, - "value": "[reference('avmContainerRegistry').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_NAME.value)]" }, "CONTAINER_REGISTRY_LOGIN_SERVER": { "type": "string", - "metadata": { - "description": "The login server of the Azure Container Registry." - }, - "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value)]" }, "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { "type": "string", - "metadata": { - "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." - }, - "value": "[reference('avmAiServices').outputs.name.value]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value)]" }, "AZURE_RESOURCE_GROUP": { "type": "string", - "metadata": { - "description": "The resource group the resources were deployed into." - }, - "value": "[resourceGroup().name]" + "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.AZURE_RESOURCE_GROUP.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.AZURE_RESOURCE_GROUP.value)]" } } } \ No newline at end of file diff --git a/infra/modules/account/aifoundry.bicep b/infra/modules/account/aifoundry.bicep deleted file mode 100644 index 4342f5f9..00000000 --- a/infra/modules/account/aifoundry.bicep +++ /dev/null @@ -1,421 +0,0 @@ -metadata name = 'Cognitive Services' -metadata description = 'This module deploys a Cognitive Service.' - -@description('Required. The name of Cognitive Services account.') -param name string - -@description('Optional: Name for the project which needs to be created.') -param projectName string - -@description('Optional: Description for the project which needs to be created.') -param projectDescription string - -param existingFoundryProjectResourceId string = '' - -@description('Required. Kind of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') -@allowed([ - 'AIServices' - 'AnomalyDetector' - 'CognitiveServices' - 'ComputerVision' - 'ContentModerator' - 'ContentSafety' - 'ConversationalLanguageUnderstanding' - 'CustomVision.Prediction' - 'CustomVision.Training' - 'Face' - 'FormRecognizer' - 'HealthInsights' - 'ImmersiveReader' - 'Internal.AllInOne' - 'LUIS' - 'LUIS.Authoring' - 'LanguageAuthoring' - 'MetricsAdvisor' - 'OpenAI' - 'Personalizer' - 'QnAMaker.v2' - 'SpeechServices' - 'TextAnalytics' - 'TextTranslation' -]) -param kind string - -@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') -@allowed([ - 'C2' - 'C3' - 'C4' - 'F0' - 'F1' - 'S' - 'S0' - 'S1' - 'S10' - 'S2' - 'S3' - 'S4' - 'S5' - 'S6' - 'S7' - 'S8' - 'S9' -]) -param sku string = 'S0' - -@description('Optional. Location for all Resources.') -param location string = resourceGroup().location - -import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The diagnostic settings of the service.') -param diagnosticSettings diagnosticSettingFullType[]? - -@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') -@allowed([ - 'Enabled' - 'Disabled' -]) -param publicNetworkAccess string? - -@description('Conditional. Subdomain name used for token-based authentication. Required if \'networkAcls\' or \'privateEndpoints\' are set.') -param customSubDomainName string? - -@description('Optional. A collection of rules governing the accessibility from specific network locations.') -param networkAcls object? - -import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') -param privateEndpoints privateEndpointSingleServiceType[]? - -import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The lock settings of the service.') -param lock lockType? - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[]? - -@description('Optional. Tags of the resource.') -param tags object? - -@description('Optional. List of allowed FQDN.') -param allowedFqdnList array? - -@description('Optional. The API properties for special APIs.') -param apiProperties object? - -@description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') -param disableLocalAuth bool = true - -import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The customer managed key definition.') -param customerManagedKey customerManagedKeyType? - -@description('Optional. The flag to enable dynamic throttling.') -param dynamicThrottlingEnabled bool = false - -@secure() -@description('Optional. Resource migration token.') -param migrationToken string? - -@description('Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists.') -param restore bool = false - -@description('Optional. Restrict outbound network access.') -param restrictOutboundNetworkAccess bool = true - -@description('Optional. The storage accounts for this resource.') -param userOwnedStorage array? - -import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The managed identity definition for this resource.') -param managedIdentities managedIdentityAllType? - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -@description('Optional. Array of deployments about cognitive service accounts to create.') -param deployments deploymentType[]? - -@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') -param secretsExportConfiguration secretsExportConfigurationType? - -@description('Optional. Enable/Disable project management feature for AI Foundry.') -param allowProjectManagement bool? - -var formattedUserAssignedIdentities = reduce( - map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), - {}, - (cur, next) => union(cur, next) -) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } - -var identity = !empty(managedIdentities) - ? { - type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') - : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) - userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null - } - : null - -#disable-next-line no-deployments-resources -resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { - name: '46d3xbcp.res.cognitiveservices-account.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } - } - } - } -} - -resource cMKKeyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { - name: last(split(customerManagedKey.?keyVaultResourceId!, '/')) - scope: resourceGroup( - split(customerManagedKey.?keyVaultResourceId!, '/')[2], - split(customerManagedKey.?keyVaultResourceId!, '/')[4] - ) - - resource cMKKey 'keys@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { - name: customerManagedKey.?keyName! - } -} - -resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { - name: last(split(customerManagedKey.?userAssignedIdentityResourceId!, '/')) - scope: resourceGroup( - split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[2], - split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[4] - ) -} - -var useExistingService = !empty(existingFoundryProjectResourceId) - -resource cognitiveServiceNew 'Microsoft.CognitiveServices/accounts@2025-12-01' = if(!useExistingService) { - name: name - kind: kind - identity: identity - location: location - tags: tags - sku: { - name: sku - } - properties: { - allowProjectManagement: allowProjectManagement // allows project management for Cognitive Services accounts in AI Foundry - FDP updates - customSubDomainName: customSubDomainName - networkAcls: !empty(networkAcls ?? {}) - ? { - defaultAction: networkAcls.?defaultAction - virtualNetworkRules: networkAcls.?virtualNetworkRules ?? [] - ipRules: networkAcls.?ipRules ?? [] - } - : null - publicNetworkAccess: publicNetworkAccess != null - ? publicNetworkAccess - : (!empty(networkAcls) ? 'Enabled' : 'Disabled') - allowedFqdnList: allowedFqdnList - apiProperties: apiProperties - disableLocalAuth: disableLocalAuth - encryption: !empty(customerManagedKey) - ? { - keySource: 'Microsoft.KeyVault' - keyVaultProperties: { - identityClientId: !empty(customerManagedKey.?userAssignedIdentityResourceId ?? '') - ? cMKUserAssignedIdentity.properties.clientId - : null - keyVaultUri: cMKKeyVault.properties.vaultUri - keyName: customerManagedKey!.keyName - keyVersion: !empty(customerManagedKey.?keyVersion ?? '') - ? customerManagedKey!.?keyVersion - : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) - } - } - : null - migrationToken: migrationToken - restore: restore - restrictOutboundNetworkAccess: restrictOutboundNetworkAccess - userOwnedStorage: userOwnedStorage - dynamicThrottlingEnabled: dynamicThrottlingEnabled - } -} - -var existingCognitiveServiceDetails = split(existingFoundryProjectResourceId, '/') - -resource cognitiveServiceExisting 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if(useExistingService) { - name: existingCognitiveServiceDetails[8] - scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) -} - -module cognitive_service_dependencies './modules/dependencies.bicep' = if(!useExistingService) { - params: { - projectName: projectName - projectDescription: projectDescription - name: cognitiveServiceNew.name - location: location - deployments: deployments - diagnosticSettings: diagnosticSettings - lock: lock - privateEndpoints: privateEndpoints - roleAssignments: roleAssignments - secretsExportConfiguration: secretsExportConfiguration - sku: sku - tags: tags - } -} - -module existing_cognitive_service_dependencies './modules/dependencies.bicep' = if(useExistingService) { - params: { - name: cognitiveServiceExisting.name - projectName: projectName - projectDescription: projectDescription - azureExistingAIProjectResourceId: existingFoundryProjectResourceId - location: location - deployments: deployments - diagnosticSettings: diagnosticSettings - lock: lock - privateEndpoints: privateEndpoints - roleAssignments: roleAssignments - secretsExportConfiguration: secretsExportConfiguration - sku: sku - tags: tags - } - scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) -} - -var cognitiveService = useExistingService ? cognitiveServiceExisting : cognitiveServiceNew - -@description('The name of the cognitive services account.') -output name string = useExistingService ? cognitiveServiceExisting.name : cognitiveServiceNew.name - -@description('The resource ID of the cognitive services account.') -output resourceId string = useExistingService ? cognitiveServiceExisting.id : cognitiveServiceNew.id - -@description('The resource group the cognitive services account was deployed into.') -output subscriptionId string = useExistingService ? existingCognitiveServiceDetails[2] : subscription().subscriptionId - -@description('The resource group the cognitive services account was deployed into.') -output resourceGroupName string = useExistingService ? existingCognitiveServiceDetails[4] : resourceGroup().name - -@description('The service endpoint of the cognitive services account.') -output endpoint string = useExistingService ? cognitiveServiceExisting.properties.endpoint : cognitiveService.properties.endpoint - -@description('All endpoints available for the cognitive services account, types depends on the cognitive service kind.') -output endpoints endpointType = useExistingService ? cognitiveServiceExisting.properties.endpoints : cognitiveService.properties.endpoints - -@description('The principal ID of the system assigned identity.') -output systemAssignedMIPrincipalId string? = useExistingService ? cognitiveServiceExisting.identity.principalId : cognitiveService.?identity.?principalId - -@description('The location the resource was deployed into.') -output location string = useExistingService ? cognitiveServiceExisting.location : cognitiveService.location - -import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') -output exportedSecrets secretsOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.exportedSecrets : cognitive_service_dependencies.outputs.exportedSecrets - -@description('The private endpoints of the congitive services account.') -output privateEndpoints privateEndpointOutputType[] = useExistingService ? existing_cognitive_service_dependencies.outputs.privateEndpoints : cognitive_service_dependencies.outputs.privateEndpoints - -import { aiProjectOutputType } from './modules/project.bicep' -output aiProjectInfo aiProjectOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.aiProjectInfo : cognitive_service_dependencies.outputs.aiProjectInfo - -// ================ // -// Definitions // -// ================ // - -@export() -@description('The type for the private endpoint output.') -type privateEndpointOutputType = { - @description('The name of the private endpoint.') - name: string - - @description('The resource ID of the private endpoint.') - resourceId: string - - @description('The group Id for the private endpoint Group.') - groupId: string? - - @description('The custom DNS configurations of the private endpoint.') - customDnsConfigs: { - @description('FQDN that resolves to private endpoint IP address.') - fqdn: string? - - @description('A list of private IP addresses of the private endpoint.') - ipAddresses: string[] - }[] - - @description('The IDs of the network interfaces associated with the private endpoint.') - networkInterfaceResourceIds: string[] -} - -@export() -@description('The type for a cognitive services account deployment.') -type deploymentType = { - @description('Optional. Specify the name of cognitive service account deployment.') - name: string? - - @description('Required. Properties of Cognitive Services account deployment model.') - model: { - @description('Required. The name of Cognitive Services account deployment model.') - name: string - - @description('Required. The format of Cognitive Services account deployment model.') - format: string - - @description('Required. The version of Cognitive Services account deployment model.') - version: string - } - - @description('Optional. The resource model definition representing SKU.') - sku: { - @description('Required. The name of the resource model definition representing SKU.') - name: string - - @description('Optional. The capacity of the resource model definition representing SKU.') - capacity: int? - - @description('Optional. The tier of the resource model definition representing SKU.') - tier: string? - - @description('Optional. The size of the resource model definition representing SKU.') - size: string? - - @description('Optional. The family of the resource model definition representing SKU.') - family: string? - }? - - @description('Optional. The name of RAI policy.') - raiPolicyName: string? - - @description('Optional. The version upgrade option.') - versionUpgradeOption: string? -} - -@export() -@description('The type for a cognitive services account endpoint.') -type endpointType = { - @description('Type of the endpoint.') - name: string? - @description('The endpoint URI.') - endpoint: string? -} - -@export() -@description('The type of the secrets exported to the provided Key Vault.') -type secretsExportConfigurationType = { - @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') - keyVaultResourceId: string - - @description('Optional. The name for the accessKey1 secret to create.') - accessKey1Name: string? - - @description('Optional. The name for the accessKey2 secret to create.') - accessKey2Name: string? -} diff --git a/infra/modules/account/modules/dependencies.bicep b/infra/modules/account/modules/dependencies.bicep deleted file mode 100644 index 55bb9ff7..00000000 --- a/infra/modules/account/modules/dependencies.bicep +++ /dev/null @@ -1,479 +0,0 @@ -@description('Required. The name of Cognitive Services account.') -param name string - -@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') -@allowed([ - 'C2' - 'C3' - 'C4' - 'F0' - 'F1' - 'S' - 'S0' - 'S1' - 'S10' - 'S2' - 'S3' - 'S4' - 'S5' - 'S6' - 'S7' - 'S8' - 'S9' -]) -param sku string = 'S0' - -@description('Optional. Location for all Resources.') -param location string = resourceGroup().location - -@description('Optional. Tags of the resource.') -param tags object? - -@description('Optional. Array of deployments about cognitive service accounts to create.') -param deployments deploymentType[]? - -@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') -param secretsExportConfiguration secretsExportConfigurationType? - -import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') -param privateEndpoints privateEndpointSingleServiceType[]? - -import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The lock settings of the service.') -param lock lockType? - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[]? - -import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. The diagnostic settings of the service.') -param diagnosticSettings diagnosticSettingFullType[]? - -@description('Optional: Name for the project which needs to be created.') -param projectName string - -@description('Optional: Description for the project which needs to be created.') -param projectDescription string - -@description('Optional: Provide the existing project resource id in case if it needs to be reused') -param azureExistingAIProjectResourceId string = '' - -var builtInRoleNames = { - 'Cognitive Services Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68' - ) - 'Cognitive Services Custom Vision Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3' - ) - 'Cognitive Services Custom Vision Deployment': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '5c4089e1-6d96-4d2f-b296-c1bc7137275f' - ) - 'Cognitive Services Custom Vision Labeler': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '88424f51-ebe7-446f-bc41-7fa16989e96c' - ) - 'Cognitive Services Custom Vision Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '93586559-c37d-4a6b-ba08-b9f0940c2d73' - ) - 'Cognitive Services Custom Vision Trainer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b' - ) - 'Cognitive Services Data Reader (Preview)': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'b59867f0-fa02-499b-be73-45a86b5b3e1c' - ) - 'Cognitive Services Face Recognizer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '9894cab4-e18a-44aa-828b-cb588cd6f2d7' - ) - 'Cognitive Services Immersive Reader User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'b2de6794-95db-4659-8781-7e080d3f2b9d' - ) - 'Cognitive Services Language Owner': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f07febfe-79bc-46b1-8b37-790e26e6e498' - ) - 'Cognitive Services Language Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '7628b7b8-a8b2-4cdc-b46f-e9b35248918e' - ) - 'Cognitive Services Language Writer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8' - ) - 'Cognitive Services LUIS Owner': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f72c8140-2111-481c-87ff-72b910f6e3f8' - ) - 'Cognitive Services LUIS Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '18e81cdc-4e98-4e29-a639-e7d10c5a6226' - ) - 'Cognitive Services LUIS Writer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '6322a993-d5c9-4bed-b113-e49bbea25b27' - ) - 'Cognitive Services Metrics Advisor Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'cb43c632-a144-4ec5-977c-e80c4affc34a' - ) - 'Cognitive Services Metrics Advisor User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '3b20f47b-3825-43cb-8114-4bd2201156a8' - ) - 'Cognitive Services OpenAI Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'a001fd3d-188f-4b5d-821b-7da978bf7442' - ) - 'Cognitive Services OpenAI User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' - ) - 'Cognitive Services QnA Maker Editor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f4cc2bf9-21be-47a1-bdf1-5c5804381025' - ) - 'Cognitive Services QnA Maker Reader': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '466ccd10-b268-4a11-b098-b4849f024126' - ) - 'Cognitive Services Speech Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '0e75ca1e-0464-4b4d-8b93-68208a576181' - ) - 'Cognitive Services Speech User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f2dc8367-1007-4938-bd23-fe263f013447' - ) - 'Cognitive Services User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'a97b65f3-24c7-4388-baec-2e87135dc908' - ) - 'Azure AI Developer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '64702f94-c441-49e6-a78b-ef80e0188fee' - ) - Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') - Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') - Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - 'Role Based Access Control Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' - ) - 'User Access Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' - ) -} - -var formattedRoleAssignments = [ - for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { - roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( - roleAssignment.roleDefinitionIdOrName, - '/providers/Microsoft.Authorization/roleDefinitions/' - ) - ? roleAssignment.roleDefinitionIdOrName - : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) - }) -] - -var enableReferencedModulesTelemetry = false - -resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { - name: name -} - -@batchSize(1) -resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = [ - for (deployment, index) in (deployments ?? []): { - parent: cognitiveService - name: deployment.?name ?? '${name}-deployments' - properties: { - model: deployment.model - raiPolicyName: deployment.?raiPolicyName - versionUpgradeOption: deployment.?versionUpgradeOption - } - sku: deployment.?sku ?? { - name: sku - capacity: sku.?capacity - tier: sku.?tier - size: sku.?size - family: sku.?family - } - } -] - -resource cognitiveService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { - name: lock.?name ?? 'lock-${name}' - properties: { - level: lock.?kind ?? '' - notes: lock.?kind == 'CanNotDelete' - ? 'Cannot delete resource or child resources.' - : 'Cannot delete or modify the resource or child resources.' - } - scope: cognitiveService -} - -resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ - for (diagnosticSetting, index) in (diagnosticSettings ?? []): { - name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' - properties: { - storageAccountId: diagnosticSetting.?storageAccountResourceId - workspaceId: diagnosticSetting.?workspaceResourceId - eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId - eventHubName: diagnosticSetting.?eventHubName - metrics: [ - for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { - category: group.category - enabled: group.?enabled ?? true - timeGrain: null - } - ] - logs: [ - for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { - categoryGroup: group.?categoryGroup - category: group.?category - enabled: group.?enabled ?? true - } - ] - marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId - logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType - } - scope: cognitiveService - } -] - -module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.12.0' = [ - for (privateEndpoint, index) in (privateEndpoints ?? []): { - name: '${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}' - scope: resourceGroup( - split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], - split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] - ) - params: { - name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' - privateLinkServiceConnections: privateEndpoint.?isManualConnection != true - ? [ - { - name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' - properties: { - privateLinkServiceId: cognitiveService.id - groupIds: [ - privateEndpoint.?service ?? 'account' - ] - } - } - ] - : null - manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true - ? [ - { - name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' - properties: { - privateLinkServiceId: cognitiveService.id - groupIds: [ - privateEndpoint.?service ?? 'account' - ] - requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' - } - } - ] - : null - subnetResourceId: privateEndpoint.subnetResourceId - enableTelemetry: enableReferencedModulesTelemetry - location: privateEndpoint.?location ?? reference( - split(privateEndpoint.subnetResourceId, '/subnets/')[0], - '2020-06-01', - 'Full' - ).location - lock: privateEndpoint.?lock ?? lock - privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup - roleAssignments: privateEndpoint.?roleAssignments - tags: privateEndpoint.?tags ?? tags - customDnsConfigs: privateEndpoint.?customDnsConfigs - ipConfigurations: privateEndpoint.?ipConfigurations - applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds - customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName - } - } -] - -resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ - for (roleAssignment, index) in (formattedRoleAssignments ?? []): { - name: roleAssignment.?name ?? guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) - properties: { - roleDefinitionId: roleAssignment.roleDefinitionId - principalId: roleAssignment.principalId - description: roleAssignment.?description - principalType: roleAssignment.?principalType - condition: roleAssignment.?condition - conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set - delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId - } - scope: cognitiveService - } -] - -module secretsExport './keyVaultExport.bicep' = if (secretsExportConfiguration != null) { - name: '${uniqueString(deployment().name, location)}-secrets-kv' - scope: resourceGroup( - split(secretsExportConfiguration.?keyVaultResourceId!, '/')[2], - split(secretsExportConfiguration.?keyVaultResourceId!, '/')[4] - ) - params: { - keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId!, '/')) - secretsToSet: union( - [], - contains(secretsExportConfiguration!, 'accessKey1Name') - ? [ - { - name: secretsExportConfiguration!.?accessKey1Name - value: cognitiveService.listKeys().key1 - } - ] - : [], - contains(secretsExportConfiguration!, 'accessKey2Name') - ? [ - { - name: secretsExportConfiguration!.?accessKey2Name - value: cognitiveService.listKeys().key2 - } - ] - : [] - ) - } -} - -module aiProject 'project.bicep' = if(!empty(projectName) || !empty(azureExistingAIProjectResourceId)) { - name: take('${name}-ai-project-${projectName}-deployment', 64) - params: { - name: projectName - desc: projectDescription - aiServicesName: cognitiveService.name - location: location - tags: tags - azureExistingAIProjectResourceId: azureExistingAIProjectResourceId - } -} - -import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') -output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) - ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) - : {} - -@description('The private endpoints of the congitive services account.') -output privateEndpoints privateEndpointOutputType[] = [ - for (pe, index) in (privateEndpoints ?? []): { - name: cognitiveService_privateEndpoints[index].outputs.name - resourceId: cognitiveService_privateEndpoints[index].outputs.resourceId - groupId: cognitiveService_privateEndpoints[index].outputs.?groupId! - customDnsConfigs: cognitiveService_privateEndpoints[index].outputs.customDnsConfigs - networkInterfaceResourceIds: cognitiveService_privateEndpoints[index].outputs.networkInterfaceResourceIds - } -] - -import { aiProjectOutputType } from 'project.bicep' -output aiProjectInfo aiProjectOutputType = aiProject.outputs.aiProjectInfo - -// ================ // -// Definitions // -// ================ // - -@export() -@description('The type for the private endpoint output.') -type privateEndpointOutputType = { - @description('The name of the private endpoint.') - name: string - - @description('The resource ID of the private endpoint.') - resourceId: string - - @description('The group Id for the private endpoint Group.') - groupId: string? - - @description('The custom DNS configurations of the private endpoint.') - customDnsConfigs: { - @description('FQDN that resolves to private endpoint IP address.') - fqdn: string? - - @description('A list of private IP addresses of the private endpoint.') - ipAddresses: string[] - }[] - - @description('The IDs of the network interfaces associated with the private endpoint.') - networkInterfaceResourceIds: string[] -} - -@export() -@description('The type for a cognitive services account deployment.') -type deploymentType = { - @description('Optional. Specify the name of cognitive service account deployment.') - name: string? - - @description('Required. Properties of Cognitive Services account deployment model.') - model: { - @description('Required. The name of Cognitive Services account deployment model.') - name: string - - @description('Required. The format of Cognitive Services account deployment model.') - format: string - - @description('Required. The version of Cognitive Services account deployment model.') - version: string - } - - @description('Optional. The resource model definition representing SKU.') - sku: { - @description('Required. The name of the resource model definition representing SKU.') - name: string - - @description('Optional. The capacity of the resource model definition representing SKU.') - capacity: int? - - @description('Optional. The tier of the resource model definition representing SKU.') - tier: string? - - @description('Optional. The size of the resource model definition representing SKU.') - size: string? - - @description('Optional. The family of the resource model definition representing SKU.') - family: string? - }? - - @description('Optional. The name of RAI policy.') - raiPolicyName: string? - - @description('Optional. The version upgrade option.') - versionUpgradeOption: string? -} - -@export() -@description('The type for a cognitive services account endpoint.') -type endpointType = { - @description('Type of the endpoint.') - name: string? - @description('The endpoint URI.') - endpoint: string? -} - -@export() -@description('The type of the secrets exported to the provided Key Vault.') -type secretsExportConfigurationType = { - @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') - keyVaultResourceId: string - - @description('Optional. The name for the accessKey1 secret to create.') - accessKey1Name: string? - - @description('Optional. The name for the accessKey2 secret to create.') - accessKey2Name: string? -} diff --git a/infra/modules/account/modules/keyVaultExport.bicep b/infra/modules/account/modules/keyVaultExport.bicep deleted file mode 100644 index ccbcf14b..00000000 --- a/infra/modules/account/modules/keyVaultExport.bicep +++ /dev/null @@ -1,43 +0,0 @@ -// ============== // -// Parameters // -// ============== // - -@description('Required. The name of the Key Vault to set the secrets in.') -param keyVaultName string - -import { secretToSetType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Required. The secrets to set in the Key Vault.') -param secretsToSet secretToSetType[] - -// ============= // -// Resources // -// ============= // - -resource keyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = { - name: keyVaultName -} - -resource secrets 'Microsoft.KeyVault/vaults/secrets@2026-02-01' = [ - for secret in secretsToSet: { - name: secret.name - parent: keyVault - properties: { - value: secret.value - } - } -] - -// =========== // -// Outputs // -// =========== // - -import { secretSetOutputType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('The references to the secrets exported to the provided Key Vault.') -output secretsSet secretSetOutputType[] = [ - #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value - for index in range(0, length(secretsToSet ?? [])): { - secretResourceId: secrets[index].id - secretUri: secrets[index].properties.secretUri - secretUriWithVersion: secrets[index].properties.secretUriWithVersion - } -] diff --git a/infra/modules/account/modules/project.bicep b/infra/modules/account/modules/project.bicep deleted file mode 100644 index 3a1620d2..00000000 --- a/infra/modules/account/modules/project.bicep +++ /dev/null @@ -1,62 +0,0 @@ -@description('Required. Name of the AI Services project.') -param name string - -@description('Required. The location of the Project resource.') -param location string = resourceGroup().location - -@description('Optional. The description of the AI Foundry project to create. Defaults to the project name.') -param desc string = name - -@description('Required. Name of the existing Cognitive Services resource to create the AI Foundry project in.') -param aiServicesName string - -@description('Optional. Tags to be applied to the resources.') -param tags object = {} - -@description('Optional. Use this parameter to use an existing AI project resource ID from different resource group') -param azureExistingAIProjectResourceId string = '' - -// // Extract components from existing AI Project Resource ID if provided -var useExistingProject = !empty(azureExistingAIProjectResourceId) -var existingProjName = useExistingProject ? last(split(azureExistingAIProjectResourceId, '/')) : '' -var existingProjEndpoint = useExistingProject ? format('https://{0}.services.ai.azure.com/api/projects/{1}', aiServicesName, existingProjName) : '' - -// Reference to cognitive service in current resource group for new projects -resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { - name: aiServicesName -} - -// Create new AI project only if not reusing existing one -resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = if(!useExistingProject) { - parent: cogServiceReference - name: name - tags: tags - location: location - identity: { - type: 'SystemAssigned' - } - properties: { - description: desc - displayName: name - } -} - -@description('AI Project metadata including name, resource ID, and API endpoint.') -output aiProjectInfo aiProjectOutputType = { - name: useExistingProject ? existingProjName : aiProject.name - resourceId: useExistingProject ? azureExistingAIProjectResourceId : aiProject.id - apiEndpoint: useExistingProject ? existingProjEndpoint : aiProject.properties.endpoints['AI Foundry API'] -} - -@export() -@description('Output type representing AI project information.') -type aiProjectOutputType = { - @description('Required. Name of the AI project.') - name: string - - @description('Required. Resource ID of the AI project.') - resourceId: string - - @description('Required. API endpoint for the AI project.') - apiEndpoint: string -} diff --git a/infra/modules/container-registry.bicep b/infra/modules/container-registry.bicep deleted file mode 100644 index 52ee5c2b..00000000 --- a/infra/modules/container-registry.bicep +++ /dev/null @@ -1,92 +0,0 @@ -metadata name = 'Container Registry Module' -// AVM-compliant Azure Container Registry deployment - -@description('Required. The name of the Azure Container Registry.') -param acrName string - -@description('Required. The location of the Azure Container Registry.') -param location string - -@description('Optional. SKU for the Azure Container Registry.') -param acrSku string = 'Basic' - -@description('Optional. Public network access setting for the Azure Container Registry.') -param publicNetworkAccess string = 'Enabled' - -@description('Optional. Zone redundancy setting for the Azure Container Registry.') -param zoneRedundancy string = 'Disabled' - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[]? - -@description('Optional. Tags to be applied to the Container Registry.') -param tags object = {} - -@description('Required. Enable telemetry for the AVM deployment.') -param enableTelemetry bool - -@description('Required. Enable Redundancy for the AVM deployment.') -param enableRedundancy bool - -@description('Required. The replica location for the Azure Container Registry replication, if redundancy is enabled.') -param replicaLocation string - -@description('Optional. Enable private networking for the Container Registry.') -param enablePrivateNetworking bool = false - -@description('Optional. Backend subnet resource ID for private endpoints.') -param backendSubnetResourceId string = '' - -@description('Optional. Private DNS zone resource ID for Container Registry.') -param privateDnsZoneResourceId string = '' - -module avmContainerRegistry 'br/public:avm/res/container-registry/registry:0.12.1' = { - name: acrName - params: { - name: acrName - location: location - acrSku: acrSku - publicNetworkAccess: publicNetworkAccess - zoneRedundancy: zoneRedundancy - roleAssignments: roleAssignments - tags: tags - enableTelemetry: enableTelemetry - replications: enableRedundancy - ? [ - { - location: replicaLocation - name: 'acrrepl${replace(replicaLocation, '-', '')}' - } - ] - : null - // WAF aligned configuration for Private Networking - Network access restrictions - // Network rule set features require Premium SKU; default action is always set ('Deny' for private networking, otherwise 'Allow'), while additional restrictions are only set when private networking is enabled - networkRuleSetDefaultAction: enablePrivateNetworking ? 'Deny' : 'Allow' - networkRuleSetIpRules: enablePrivateNetworking ? [] : null - exportPolicyStatus: enablePrivateNetworking ? 'disabled' : null - privateEndpoints: enablePrivateNetworking - ? [ - { - name: 'pep-acr-${acrName}' - customNetworkInterfaceName: 'nic-acr-${acrName}' - privateDnsZoneGroup: !empty(privateDnsZoneResourceId) - ? { - privateDnsZoneGroupConfigs: [ - { - name: 'acr-dns-zone-group' - privateDnsZoneResourceId: privateDnsZoneResourceId - } - ] - } - : null - subnetResourceId: backendSubnetResourceId - } - ] - : [] - } -} - -output name string = avmContainerRegistry.outputs.name -output resourceId string = avmContainerRegistry.outputs.resourceId -output loginServer string = avmContainerRegistry.outputs.loginServer diff --git a/infra/modules/log-analytics-workspace.bicep b/infra/modules/log-analytics-workspace.bicep deleted file mode 100644 index 6b1c51e9..00000000 --- a/infra/modules/log-analytics-workspace.bicep +++ /dev/null @@ -1,105 +0,0 @@ -@description('The name of Log analytics Workspace') -param name string - -@description('Location for the Resource.') -param location string = resourceGroup().location - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -@description('Optional. Tags to be applied to the resources.') -param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} - -@description('Optional: Existing Log Analytics Workspace Resource ID') -param existingLogAnalyticsWorkspaceId string = '' - -@description('Optional. Enable Private Networking for Log Analytics Workspace.') -param enablePrivateNetworking bool = false - -@description('Optional. Enable Redundancy for Log Analytics Workspace.') -param enableRedundancy bool = false - -@description('Optional. The replica location for Log Analytics Workspace, if redundancy is enabled.') -param replicaLocation string = '' - -var useExistingWorkspace = !empty(existingLogAnalyticsWorkspaceId) - -var existingLawSubscription = useExistingWorkspace ? split(existingLogAnalyticsWorkspaceId, '/')[2] : '' -var existingLawResourceGroup = useExistingWorkspace ? split(existingLogAnalyticsWorkspaceId, '/')[4] : '' -var existingLawName = useExistingWorkspace ? split(existingLogAnalyticsWorkspaceId, '/')[8] : '' - -module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.15.0' = if (!useExistingWorkspace) { - name: take('avm.res.operational-insights.workspace.${name}', 64) - params: { - name: name - tags: tags - location: location - enableTelemetry: enableTelemetry - skuName: 'PerGB2018' - dataRetention: 365 - features: { enableLogAccessUsingOnlyResourcePermissions: true } - diagnosticSettings: [{ useThisWorkspace: true }] - // WAF aligned configuration for Redundancy - dailyQuotaGb: enableRedundancy ? '150' : null //WAF recommendation: 150 GB per day is a good starting point for most workloads - replication: enableRedundancy - ? { - enabled: true - location: replicaLocation - } - : null - // WAF aligned configuration for Private Networking - publicNetworkAccessForIngestion: enablePrivateNetworking ? 'Disabled' : 'Enabled' - publicNetworkAccessForQuery: enablePrivateNetworking ? 'Disabled' : 'Enabled' - dataSources: enablePrivateNetworking - ? [ - { - tags: tags - eventLogName: 'Application' - eventTypes: [ - { - eventType: 'Error' - } - { - eventType: 'Warning' - } - { - eventType: 'Information' - } - ] - kind: 'WindowsEvent' - name: 'applicationEvent' - } - { - counterName: '% Processor Time' - instanceName: '*' - intervalSeconds: 60 - kind: 'WindowsPerformanceCounter' - name: 'windowsPerfCounter1' - objectName: 'Processor' - } - { - kind: 'IISLogs' - name: 'sampleIISLog1' - state: 'OnPremiseEnabled' - } - ] - : null - } -} - -resource existingLogAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2025-07-01' existing = if (useExistingWorkspace) { - name: existingLawName - scope: resourceGroup(existingLawSubscription, existingLawResourceGroup) -} - -var lawKeys = useExistingWorkspace ? listKeys(existingLogAnalyticsWorkspace.id, '2020-08-01') : logAnalyticsWorkspace.outputs.primarySharedKey - -output resourceId string = useExistingWorkspace ? existingLogAnalyticsWorkspace.id : logAnalyticsWorkspace.outputs.resourceId -output logAnalyticsWorkspaceId string = useExistingWorkspace ? existingLogAnalyticsWorkspace.properties.customerId : logAnalyticsWorkspace.outputs.logAnalyticsWorkspaceId -@secure() -output primarySharedKey string = useExistingWorkspace ? lawKeys.primarySharedKey : logAnalyticsWorkspace.outputs.primarySharedKey -output location string = useExistingWorkspace ? existingLogAnalyticsWorkspace!.location : logAnalyticsWorkspace!.outputs.location -output name string = useExistingWorkspace ? existingLogAnalyticsWorkspace!.name : logAnalyticsWorkspace!.outputs.name diff --git a/infra/modules/managed-identity.bicep b/infra/modules/managed-identity.bicep deleted file mode 100644 index aa6e4915..00000000 --- a/infra/modules/managed-identity.bicep +++ /dev/null @@ -1,25 +0,0 @@ -// ========== Managed Identity ========== // -@description('Required. The name of the managed identity.') -param name string - -@description('Required. The location of the managed identity.') -param location string - -@description('Required. Tags to be applied to the managed identity.') -param tags object - -@description('Required. Enable telemetry for the AVM deployment.') -param enableTelemetry bool - -module avmManagedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { - name: name - params: { - name: name - location: location - tags: tags - enableTelemetry: enableTelemetry - } -} - -output resourceId string = avmManagedIdentity.outputs.resourceId -output principalId string = avmManagedIdentity.outputs.principalId diff --git a/infra/modules/virtualNetwork.bicep b/infra/modules/virtualNetwork.bicep deleted file mode 100644 index a15a385a..00000000 --- a/infra/modules/virtualNetwork.bicep +++ /dev/null @@ -1,397 +0,0 @@ -/****************************************************************************************************************************/ -// Networking - NSGs, VNET and Subnets. Each subnet has its own NSG -/****************************************************************************************************************************/ -@description('Required. Name of the virtual network.') -param name string - -@description('Optional. Azure region to deploy resources.') -param location string = resourceGroup().location - -@description('Required. An Array of 1 or more IP Address Prefixes for the Virtual Network.') -param addressPrefixes array - -@description('Optional. An array of subnets to be created within the virtual network. Each subnet can have its own configuration and associated Network Security Group (NSG).') -param subnets subnetType[] = [ - { - name: 'containers' - addressPrefixes: ['10.0.2.0/24'] // /24 (10.0.2.0 - 10.0.2.255), 256 addresses - delegation: 'Microsoft.App/environments' - networkSecurityGroup: { - name: 'nsg-containers' - securityRules: [ - //Inbound Rules - { - name: 'AllowHttpsInbound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 100 - protocol: 'Tcp' - sourceAddressPrefix: 'Internet' - sourcePortRange: '*' - destinationPortRanges: ['443', '80'] - destinationAddressPrefixes: ['10.0.2.0/24'] - } - } - { - name: 'AllowAzureLoadBalancerInbound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 102 - protocol: '*' - sourceAddressPrefix: 'AzureLoadBalancer' - sourcePortRange: '*' - destinationPortRanges: ['30000-32767'] - destinationAddressPrefixes: ['10.0.2.0/24'] - } - } - { - name: 'AllowSideCarsInbound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 103 - protocol: '*' - sourcePortRange: '*' - sourceAddressPrefixes: ['10.0.2.0/24'] - destinationPortRange: '*' - destinationAddressPrefix: '*' - } - } - //Outbound Rules - { - name: 'AllowOutboundToAzureServices' - properties: { - access: 'Allow' - direction: 'Outbound' - priority: 200 - protocol: '*' - sourceAddressPrefixes: ['10.0.2.0/24'] - sourcePortRange: '*' - destinationPortRange: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'deny-hop-outbound' - properties: { - access: 'Deny' - direction: 'Outbound' - priority: 100 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['3389', '22'] - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: '*' - } - } - ] - } - } - { - name: 'backend' - addressPrefixes: ['10.0.0.0/24'] // /24 (10.0.0.0 - 10.0.0.255), 256 addresses - privateEndpointNetworkPolicies: 'Disabled' - privateLinkServiceNetworkPolicies: 'Disabled' - networkSecurityGroup: { - name: 'nsg-backend' - securityRules: [ - { - name: 'Deny-hop-outbound' - properties: { - access: 'Deny' - direction: 'Outbound' - priority: 200 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['3389', '22'] - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: '*' - } - } - ] - } - } - { - name: 'AzureBastionSubnet' // Required name for Azure Bastion - addressPrefixes: ['10.0.1.32/27'] - networkSecurityGroup: { - name: 'nsg-bastion' - securityRules: [ - { - name: 'AllowGatewayManager' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 2702 - protocol: '*' - sourcePortRange: '*' - destinationPortRange: '443' - sourceAddressPrefix: 'GatewayManager' - destinationAddressPrefix: '*' - } - } - { - name: 'AllowHttpsInBound' - properties: { - access: 'Allow' - direction: 'Inbound' - priority: 2703 - protocol: '*' - sourcePortRange: '*' - destinationPortRange: '443' - sourceAddressPrefix: 'Internet' - destinationAddressPrefix: '*' - } - } - { - name: 'AllowSshRdpOutbound' - properties: { - access: 'Allow' - direction: 'Outbound' - priority: 100 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['22', '3389'] - sourceAddressPrefix: '*' - destinationAddressPrefix: 'VirtualNetwork' - } - } - { - name: 'AllowAzureCloudOutbound' - properties: { - access: 'Allow' - direction: 'Outbound' - priority: 110 - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '443' - sourceAddressPrefix: '*' - destinationAddressPrefix: 'AzureCloud' - } - } - ] - } - } - { - name: 'admin' - addressPrefixes: ['10.0.1.0/27'] - networkSecurityGroup: { - name: 'nsg-admin' - securityRules: [ - { - name: 'Deny-hop-outbound' - properties: { - access: 'Deny' - direction: 'Outbound' - priority: 200 - protocol: '*' - sourcePortRange: '*' - destinationPortRanges: ['3389', '22'] - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: '*' - } - } - ] - } - } -] - -@description('Optional. Tags to be applied to the resources.') -param tags object = {} - -@description('Required. The resource ID of the Log Analytics Workspace to send diagnostic logs to.') -param logAnalyticsWorkspaceId string - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -@description('Required. Suffix for resource naming.') -param resourceSuffix string - -// VM Size Notes: -// 1 B-series VMs (like Standard_B2ms) do not support accelerated networking. -// 2 Pick a VM size that supports accelerated networking + Premium SSD (the usual jump-box candidates): -// Standard_D2s_v5 (2 vCPU, 8 GiB RAM, Premium SSD/v2/Ultra) // DEFAULT - current-gen Intel, broad regional availability. -// Standard_D2as_v5 (2 vCPU, 8 GiB RAM, Premium SSD/Ultra) // AMD alternative, typically ~15% cheaper. -// Standard_D2s_v4 (2 vCPU, 8 GiB RAM, Premium SSD) // Previous gen, also broadly available. -// Standard_DS2_v2 (2 vCPU, 7 GiB RAM, Premium SSD) // Legacy SKU, being retired from some regions - avoid for new deployments. -// 3 A-series (Av2) is NOT suitable: no Premium SSD support, no accelerated networking. - -// Subnet Classless Inter-Doman Routing (CIDR) Sizing Reference Table (Best Practices) -// | CIDR | # of Addresses | # of /24s | Notes | -// |-----------|---------------|-----------|----------------------------------------| -// | /24 | 256 | 1 | Smallest recommended for Azure subnets | -// | /23 | 512 | 2 | Good for 1-2 workloads per subnet | -// | /22 | 1024 | 4 | Good for 2-4 workloads per subnet | -// | /21 | 2048 | 8 | | -// | /20 | 4096 | 16 | Used for default VNet in this solution | -// | /19 | 8192 | 32 | | -// | /18 | 16384 | 64 | | -// | /17 | 32768 | 128 | | -// | /16 | 65536 | 256 | | -// | /15 | 131072 | 512 | | -// | /14 | 262144 | 1024 | | -// | /13 | 524288 | 2048 | | -// | /12 | 1048576 | 4096 | | -// | /11 | 2097152 | 8192 | | -// | /10 | 4194304 | 16384 | | -// | /9 | 8388608 | 32768 | | -// | /8 | 16777216 | 65536 | | -// -// Best Practice Notes: -// - Use /24 as the minimum subnet size for Azure (smaller subnets are not supported for most services). -// - Plan for future growth: allocate larger address spaces (e.g., /20 or /21 for VNets) to allow for new subnets. -// - Avoid overlapping address spaces with on-premises or other VNets. -// - Use contiguous, non-overlapping ranges for subnets. -// - Document subnet usage and purpose in code comments. -// - For AVM modules, ensure only one delegation per subnet and leave delegations empty if not required. - -// 1. Create NSGs for subnets -// using AVM Network Security Group module -// https://github.com/Azure/bicep-registry-modules/tree/main/avm/res/network/network-security-group - -@batchSize(1) -module nsgs 'br/public:avm/res/network/network-security-group:0.5.3' = [ - for (subnet, i) in subnets: if (!empty(subnet.?networkSecurityGroup)) { - name: take('avm.res.network.network-security-group.${subnet.?networkSecurityGroup.name}.${resourceSuffix}', 64) - params: { - name: '${subnet.?networkSecurityGroup.name}-${resourceSuffix}' - location: location - securityRules: subnet.?networkSecurityGroup.securityRules - tags: tags - enableTelemetry: enableTelemetry - } - } -] - -// 2. Create VNet and subnets, with subnets associated with corresponding NSGs -// using AVM Virtual Network module -// https://github.com/Azure/bicep-registry-modules/tree/main/avm/res/network/virtual-network - -module virtualNetwork 'br/public:avm/res/network/virtual-network:0.8.1' = { - name: take('avm.res.network.virtual-network.${name}', 64) - params: { - name: name - location: location - addressPrefixes: addressPrefixes - subnets: [ - for (subnet, i) in subnets: { - name: subnet.name - addressPrefixes: subnet.?addressPrefixes - networkSecurityGroupResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null - privateEndpointNetworkPolicies: subnet.?privateEndpointNetworkPolicies - privateLinkServiceNetworkPolicies: subnet.?privateLinkServiceNetworkPolicies - delegation: subnet.?delegation - } - ] - diagnosticSettings: [ - { - name: 'vnetDiagnostics' - workspaceResourceId: logAnalyticsWorkspaceId - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] - metricCategories: [ - { - category: 'AllMetrics' - enabled: true - } - ] - } - ] - tags: tags - enableTelemetry: enableTelemetry - } -} - -output name string = virtualNetwork.outputs.name -output resourceId string = virtualNetwork.outputs.resourceId - -// combined output array that holds subnet details along with NSG information -output subnets subnetOutputType[] = [ - for (subnet, i) in subnets: { - name: subnet.name - resourceId: virtualNetwork.outputs.subnetResourceIds[i] - nsgName: !empty(subnet.?networkSecurityGroup) ? subnet.?networkSecurityGroup.name : null - nsgResourceId: !empty(subnet.?networkSecurityGroup) ? nsgs[i]!.outputs.resourceId : null - } -] - -// Dynamic outputs for individual subnets for backward compatibility -output containersSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'containers') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'containers')] - : '' -output backendSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'backend') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'backend')] - : '' -output bastionSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'AzureBastionSubnet') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'AzureBastionSubnet')] - : '' -output adminSubnetResourceId string = contains(map(subnets, subnet => subnet.name), 'admin') - ? virtualNetwork.outputs.subnetResourceIds[indexOf(map(subnets, subnet => subnet.name), 'admin')] - : '' - -@export() -@description('Custom type definition for subnet resource information as output') -type subnetOutputType = { - @description('The name of the subnet.') - name: string - - @description('The resource ID of the subnet.') - resourceId: string - - @description('The name of the associated network security group, if any.') - nsgName: string? - - @description('The resource ID of the associated network security group, if any.') - nsgResourceId: string? -} - -@export() -@description('Custom type definition for subnet configuration') -type subnetType = { - @description('Required. The Name of the subnet resource.') - name: string - - @description('Required. Prefixes for the subnet.') // Required to ensure at least one prefix is provided - addressPrefixes: string[] - - @description('Optional. The delegation to enable on the subnet.') - delegation: string? - - @description('Optional. enable or disable apply network policies on private endpoint in the subnet.') - privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? - - @description('Optional. Enable or disable apply network policies on private link service in the subnet.') - privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? - - @description('Optional. Network Security Group configuration for the subnet.') - networkSecurityGroup: networkSecurityGroupType? - - @description('Optional. The resource ID of the route table to assign to the subnet.') - routeTableResourceId: string? - - @description('Optional. An array of service endpoint policies.') - serviceEndpointPolicies: object[]? - - @description('Optional. The service endpoints to enable on the subnet.') - serviceEndpoints: string[]? - - @description('Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet.') - defaultOutboundAccess: bool? -} - -@export() -@description('Custom type definition for network security group configuration') -type networkSecurityGroupType = { - @description('Required. The name of the network security group.') - name: string - - @description('Required. The security rules for the network security group.') - securityRules: object[] -} diff --git a/infra/scripts/post-provision/.gitkeep b/infra/scripts/post-provision/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/infra/scripts/pre-provision/.gitkeep b/infra/scripts/pre-provision/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/infra/scripts/utilities/.gitkeep b/infra/scripts/utilities/.gitkeep new file mode 100644 index 00000000..e69de29b From b36e1a9aa39302b6e8d807f7348f96f3d764347c Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Thu, 11 Jun 2026 11:30:50 +0530 Subject: [PATCH 5/8] feat(infra): update parameter files from GSA reference Copy latest main.parameters.json and main.waf.parameters.json from agentic-applications infra-core-modules-copy branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- infra/main.parameters.json | 51 +++++++++++++++++++++++++++---- infra/main.waf.parameters.json | 56 +++++++++++++++++++++++++++++----- 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/infra/main.parameters.json b/infra/main.parameters.json index 44153d57..184e9247 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -2,14 +2,17 @@ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { + "deploymentFlavor": { + "value": "${DEPLOYMENT_FLAVOR=bicep}" + }, "solutionName": { "value": "${AZURE_ENV_NAME}" }, "location": { "value": "${AZURE_LOCATION}" }, - "azureAiServiceLocation": { - "value": "${AZURE_ENV_AI_SERVICE_LOCATION}" + "secondaryLocation": { + "value": "${AZURE_ENV_SECONDARY_LOCATION}" }, "deploymentType": { "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" @@ -20,20 +23,56 @@ "gptModelVersion": { "value": "${AZURE_ENV_GPT_MODEL_VERSION}" }, + "azureOpenaiAPIVersion": { + "value": "${AZURE_ENV_OPENAI_API_VERSION}" + }, "gptDeploymentCapacity": { "value": "${AZURE_ENV_GPT_MODEL_CAPACITY}" }, + "embeddingDeploymentCapacity": { + "value": "${AZURE_ENV_EMBEDDING_DEPLOYMENT_CAPACITY}" + }, + "imageTag": { + "value": "${AZURE_ENV_IMAGE_TAG}" + }, + "enableMonitoring": { + "value": true + }, "existingLogAnalyticsWorkspaceId": { "value": "${AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID}" }, "existingFoundryProjectResourceId": { "value": "${AZURE_EXISTING_AIPROJECT_RESOURCE_ID}" }, - "containerRegistryEndpoint": { - "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" + "backendRuntimeStack": { + "value": "${BACKEND_RUNTIME_STACK}" }, - "imageTag": { - "value": "${AZURE_ENV_IMAGETAG=latest_v2}" + "azureAiServiceLocation": { + "value": "${AZURE_ENV_AI_SERVICE_LOCATION}" + }, + "containerRegistryName": { + "value": "${AZURE_ENV_CONTAINER_REGISTRY_NAME}" + }, + "searchServiceLocation": { + "value": "${AZURE_ENV_SEARCH_SERVICE_LOCATION}" + }, + "deployingUserPrincipalType": { + "value": "${DEPLOYING_USER_PRINCIPAL_TYPE=User}" + }, + "useUserAccessToken":{ + "value": "${USE_USER_ACCESS_TOKEN}" + }, + "fabricWorkspaceId": { + "value": "${FABRIC_WORKSPACE_ID}" + }, + "azureFabricCapacityName": { + "value": "${AZURE_FABRIC_CAPACITY_NAME}" + }, + "fabricCapacitySku": { + "value": "${FABRIC_CAPACITY_SKU=F2}" + }, + "fabricAdminMembers": { + "value": "${FABRIC_ADMIN_MEMBERS=[]}" } } } \ No newline at end of file diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index 8e145a07..319d7e93 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -2,14 +2,17 @@ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { + "deploymentFlavor": { + "value": "avm-waf" + }, "solutionName": { "value": "${AZURE_ENV_NAME}" }, "location": { "value": "${AZURE_LOCATION}" }, - "azureAiServiceLocation": { - "value": "${AZURE_ENV_AI_SERVICE_LOCATION}" + "secondaryLocation": { + "value": "${AZURE_ENV_SECONDARY_LOCATION}" }, "deploymentType": { "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" @@ -20,15 +23,42 @@ "gptModelVersion": { "value": "${AZURE_ENV_GPT_MODEL_VERSION}" }, + "azureOpenaiAPIVersion": { + "value": "${AZURE_ENV_OPENAI_API_VERSION}" + }, "gptDeploymentCapacity": { "value": "${AZURE_ENV_GPT_MODEL_CAPACITY}" }, + "embeddingDeploymentCapacity": { + "value": "${AZURE_ENV_EMBEDDING_DEPLOYMENT_CAPACITY}" + }, + "imageTag": { + "value": "${AZURE_ENV_IMAGE_TAG}" + }, "existingLogAnalyticsWorkspaceId": { "value": "${AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID}" }, "existingFoundryProjectResourceId": { "value": "${AZURE_EXISTING_AIPROJECT_RESOURCE_ID}" }, + "backendRuntimeStack": { + "value": "${BACKEND_RUNTIME_STACK}" + }, + "azureAiServiceLocation": { + "value": "${AZURE_ENV_AI_SERVICE_LOCATION}" + }, + "containerRegistryName": { + "value": "${AZURE_ENV_CONTAINER_REGISTRY_NAME}" + }, + "searchServiceLocation": { + "value": "${AZURE_ENV_SEARCH_SERVICE_LOCATION}" + }, + "deployingUserPrincipalType": { + "value": "${DEPLOYING_USER_PRINCIPAL_TYPE=User}" + }, + "enableTelemetry": { + "value": "${AZURE_ENV_ENABLE_TELEMETRY}" + }, "enableMonitoring": { "value": true }, @@ -38,6 +68,9 @@ "enableScalability": { "value": true }, + "enableRedundancy": { + "value": false + }, "vmAdminUsername": { "value": "${AZURE_ENV_VM_ADMIN_USERNAME}" }, @@ -47,11 +80,20 @@ "vmSize": { "value": "${AZURE_ENV_VM_SIZE}" }, - "containerRegistryEndpoint": { - "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" + "useUserAccessToken":{ + "value": "${USE_USER_ACCESS_TOKEN}" }, - "imageTag": { - "value": "${AZURE_ENV_IMAGETAG=latest_v2}" + "fabricWorkspaceId": { + "value": "${FABRIC_WORKSPACE_ID}" + }, + "azureFabricCapacityName": { + "value": "${AZURE_FABRIC_CAPACITY_NAME}" + }, + "fabricCapacitySku": { + "value": "${FABRIC_CAPACITY_SKU=F2}" + }, + "fabricAdminMembers": { + "value": "${FABRIC_ADMIN_MEMBERS=[]}" } } -} \ No newline at end of file +} From ca6ba6f80c472d662ef58c786be5aa53e243d5f7 Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Thu, 11 Jun 2026 11:55:29 +0530 Subject: [PATCH 6/8] feat(infra): reformat main.bicep files to GSA section-header structure Reorganized both infra/avm/main.bicep and infra/bicep/main.bicep to follow the GSA-compatible code structure from the reference repo: - Added section headers (Parameters, Variables, Monitoring, Networking, Identity, Security, AI, Data, Compute, Outputs) - Grouped parameters by category with @description decorators - Updated module deployment names to take('module..\', 64) pattern - Preserved all content-processing business logic and resources Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- infra/avm/main.bicep | 1882 ++++++++++++++++++++-------------------- infra/bicep/main.bicep | 483 +++++++---- 2 files changed, 1295 insertions(+), 1070 deletions(-) diff --git a/infra/avm/main.bicep b/infra/avm/main.bicep index a492c376..4a5c81b8 100644 --- a/infra/avm/main.bicep +++ b/infra/avm/main.bicep @@ -1,10 +1,16 @@ -// ========== main.bicep ========== // +// ============================================================================ +// main.bicep — Orchestrator +// Description: Pure orchestrator for Content Processing Solution Accelerator +// All resource names are derived from params — no hardcoded names. +// This file only calls modules; no inline resource definitions. +// Supports WAF-aligned deployment via feature flags. +// ============================================================================ targetScope = 'resourceGroup' -metadata name = 'Content Processing Solution Accelerator' -metadata description = 'Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance.' +// ============================================================================ +// Parameters — Core +// ============================================================================ -// ========== Parameters ========== // @minLength(3) @maxLength(20) @description('Optional. Name of the solution to deploy. This should be 3-20 characters long.') @@ -24,6 +30,62 @@ param solutionName string = 'cps' ]) param location string +@description('Optional. Tags to be applied to the resources.') +param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location +} + +@description('Optional. Tag, Created by user name.') +param createdBy string = contains(deployer(), 'userPrincipalName') + ? split(deployer().userPrincipalName, '@')[0] + : deployer().objectId + +@maxLength(5) +@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') +param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) + +// ============================================================================ +// Parameters — WAF Feature Flags +// ============================================================================ + +@description('Optional. Enable WAF for the deployment.') +param enablePrivateNetworking bool = false + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') +param enableMonitoring bool = false + +@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableRedundancy bool = false + +@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableScalability bool = false + +@description('Optional. Enable purge protection. Defaults to false.') +param enablePurgeProtection bool = false + +// ============================================================================ +// Parameters — VM +// ============================================================================ + +@description('Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true.') +param vmSize string = '' + +@description('Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') +@secure() +param vmAdminUsername string = '' + +@description('Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') +@secure() +param vmAdminPassword string = '' + +// ============================================================================ +// Parameters — AI Configuration +// ============================================================================ + @minLength(1) @allowed([ 'australiaeast' @@ -71,35 +133,19 @@ param gptModelVersion string = '2025-11-13' @description('Optional. Capacity of the GPT deployment: (minimum 10).') param gptDeploymentCapacity int = 300 +// ============================================================================ +// Parameters — Compute +// ============================================================================ + @description('Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint).') param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' @description('Optional. The image tag for the container images.') param imageTag string = 'latest_v2' -@description('Optional. Enable WAF for the deployment.') -param enablePrivateNetworking bool = false - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') -param enableMonitoring bool = false - -@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') -param enableRedundancy bool = false - -@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') -param enableScalability bool = false - -@description('Optional. Enable purge protection. Defaults to false.') -param enablePurgeProtection bool = false - -@description('Optional. Tags to be applied to the resources.') -param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} +// ============================================================================ +// Parameters — Existing Resources +// ============================================================================ @description('Optional: Existing Log Analytics Workspace Resource ID') param existingLogAnalyticsWorkspaceId string = '' @@ -107,20 +153,9 @@ param existingLogAnalyticsWorkspaceId string = '' @description('Use this parameter to use an existing AI project resource ID') param existingFoundryProjectResourceId string = '' -@description('Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true.') -param vmSize string = '' - -@description('Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') -@secure() -param vmAdminUsername string = '' - -@description('Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true.') -@secure() -param vmAdminPassword string = '' - -@maxLength(5) -@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') -param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) +// ============================================================================ +// Variables +// ============================================================================ var solutionSuffix = toLower(trim(replace( replace( @@ -131,13 +166,80 @@ var solutionSuffix = toLower(trim(replace( '*', '' ))) -// ============== // -// Resources // -// ============== // var existingProjectResourceId = trim(existingFoundryProjectResourceId) -// ========== AVM Telemetry ========== // +// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. +var replicaRegionPairs = { + australiaeast: 'australiasoutheast' + centralus: 'westus' + eastasia: 'japaneast' + eastus: 'centralus' + eastus2: 'centralus' + japaneast: 'eastasia' + northeurope: 'westeurope' + southeastasia: 'eastasia' + uksouth: 'westeurope' + westeurope: 'northeurope' +} +var replicaLocation = replicaRegionPairs[?location] + +var bastionHostName = 'bas-${solutionSuffix}' + +var jumpboxVmName = take('vm-${solutionSuffix}', 15) + +var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' +var dataCollectionRulesLocation = logAnalyticsWorkspace!.outputs.location +var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' +var dcrLogAnalyticsDestinationName = 'la-${logAnalyticsWorkspaceResourceName}-destination' + +var privateDnsZones = [ + 'privatelink.cognitiveservices.azure.com' + 'privatelink.openai.azure.com' + 'privatelink.services.ai.azure.com' + 'privatelink.contentunderstanding.ai.azure.com' + 'privatelink.blob.${environment().suffixes.storage}' + 'privatelink.queue.${environment().suffixes.storage}' + 'privatelink.mongo.cosmos.azure.com' + 'privatelink.azconfig.io' + 'privatelink.azurecr.io' +] + +// DNS Zone Index Constants +var dnsZoneIndex = { + cognitiveServices: 0 + openAI: 1 + aiServices: 2 + contentUnderstanding: 3 + storageBlob: 4 + storageQueue: 5 + cosmosDB: 6 + appConfig: 7 + containerRegistry: 8 +} + +// ============================================================================ +// Resource Group Tags +// ============================================================================ + +resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { + name: 'default' + properties: { + tags: { + ...resourceGroup().tags + ...tags + TemplateName: 'Content Processing' + Type: enablePrivateNetworking ? 'WAF' : 'Non-WAF' + CreatedBy: createdBy + DeploymentName: deployment().name + } + } +} + +// ============================================================================ +// Module: Monitoring +// ============================================================================ + #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { name: take( @@ -160,214 +262,40 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableT } } -// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. -var replicaRegionPairs = { - australiaeast: 'australiasoutheast' - centralus: 'westus' - eastasia: 'japaneast' - eastus: 'centralus' - eastus2: 'centralus' - japaneast: 'eastasia' - northeurope: 'westeurope' - southeastasia: 'eastasia' - uksouth: 'westeurope' - westeurope: 'northeurope' -} -var replicaLocation = replicaRegionPairs[?location] - -// ========== Virtual Network ========== // -module virtualNetwork './modules/networking/virtual-network.bicep' = if (enablePrivateNetworking) { - name: take('module.virtual-network.${solutionSuffix}', 64) +module logAnalyticsWorkspace './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { + name: take('module.log-analytics-workspace.${solutionSuffix}', 64) params: { solutionName: solutionSuffix - addressPrefixes: ['10.0.0.0/8'] + name: logAnalyticsWorkspaceResourceName location: location tags: tags - logAnalyticsWorkspaceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - resourceSuffix: solutionSuffix enableTelemetry: enableTelemetry + enableReplication: enableRedundancy + replicationLocation: replicaLocation } } -// Azure Bastion Host -var bastionHostName = 'bas-${solutionSuffix}' -module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePrivateNetworking) { - name: take('avm.res.network.bastion-host.${bastionHostName}', 64) +module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (enableMonitoring) { + name: take('avm.res.insights.component.${solutionSuffix}', 64) params: { - name: bastionHostName - skuName: 'Standard' + name: 'appi-${solutionSuffix}' location: location - virtualNetworkResourceId: virtualNetwork!.outputs.resourceId - diagnosticSettings: enableMonitoring - ? [ - { - name: 'bastionDiagnostics' - workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] - } - ] - : null - tags: tags enableTelemetry: enableTelemetry - publicIPAddressObject: { - name: 'pip-${bastionHostName}' - } + retentionInDays: 365 + kind: 'web' + disableIpMasking: false + flowType: 'Bluefield' + // WAF aligned configuration for Monitoring + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null + tags: tags } } -// ========== VM Maintenance Configuration Mapping ========== // - -// Jumpbox Virtual Machine -var jumpboxVmName = take('vm-${solutionSuffix}', 15) -module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enablePrivateNetworking) { - name: take('avm.res.compute.virtual-machine.${jumpboxVmName}', 64) +module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.11.0' = if (enablePrivateNetworking && enableMonitoring) { + name: take('avm.res.insights.data-collection-rule.${solutionSuffix}', 64) params: { - name: jumpboxVmName - location: location - tags: tags - enableTelemetry: enableTelemetry - computerName: take(jumpboxVmName, 15) - osType: 'Windows' - vmSize: empty(vmSize) ? 'Standard_D2s_v5' : vmSize - adminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername - adminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword - managedIdentities: { - systemAssigned: true - } - patchMode: 'AutomaticByPlatform' - bypassPlatformSafetyChecksOnUserSchedule: true - maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId - enableAutomaticUpdates: true - encryptionAtHost: false - availabilityZone: enableRedundancy ? 1 : -1 - imageReference: { - publisher: 'microsoft-dsvm' - offer: 'dsvm-win-2022' - sku: 'winserver-2022' - version: 'latest' - } - osDisk: { - name: 'osdisk-${jumpboxVmName}' - caching: 'ReadWrite' - createOption: 'FromImage' - deleteOption: 'Delete' - diskSizeGB: 128 - managedDisk: { - // WAF aligned configuration - use Premium storage for better SLA when redundancy is enabled - storageAccountType: enableRedundancy ? 'Premium_LRS' : 'Standard_LRS' - } - } - nicConfigurations: [ - { - name: 'nic-${jumpboxVmName}' - tags: tags - deleteOption: 'Delete' - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring - ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] - : null - ipConfigurations: [ - { - name: '${jumpboxVmName}-nic01-ipconfig01' - subnetResourceId: virtualNetwork!.outputs.administrationSubnetResourceId - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring - ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] - : null - } - ] - } - ] - extensionAadJoinConfig: { - enabled: true - tags: tags - typeHandlerVersion: '1.0' - settings: { - mdmId:'' - } - } - extensionAntiMalwareConfig: { - enabled: true - settings: { - AntimalwareEnabled: 'true' - Exclusions: {} - RealtimeProtectionEnabled: 'true' - ScheduledScanSettings: { - day: '7' - isEnabled: 'true' - scanType: 'Quick' - time: '120' - } - } - tags: tags - } - //WAF aligned configuration for Monitoring - extensionMonitoringAgentConfig: enableMonitoring - ? { - dataCollectionRuleAssociations: [ - { - dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId - name: 'send-${logAnalyticsWorkspace!.outputs.name}' - } - ] - enabled: true - tags: tags - } - : null - extensionNetworkWatcherAgentConfig: { - enabled: true - tags: tags - } - } -} - -module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = if (enablePrivateNetworking) { - name: take('avm.res.maintenance-configuration.${jumpboxVmName}', 64) - params: { - name: 'mc-${jumpboxVmName}' - location: location - tags: tags - enableTelemetry: enableTelemetry - extensionProperties: { - InGuestPatchMode: 'User' - } - maintenanceScope: 'InGuestPatch' - maintenanceWindow: { - startDateTime: '2024-06-16 00:00' - duration: '03:55' - timeZone: 'W. Europe Standard Time' - recurEvery: '1Day' - } - visibility: 'Custom' - installPatches: { - rebootSetting: 'IfRequired' - windowsParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } - linuxParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } - } - } -} - -var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' -var dataCollectionRulesLocation = logAnalyticsWorkspace!.outputs.location -var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' -var dcrLogAnalyticsDestinationName = 'la-${logAnalyticsWorkspaceResourceName}-destination' -module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.11.0' = if (enablePrivateNetworking && enableMonitoring) { - name: take('avm.res.insights.data-collection-rule.${dataCollectionRulesResourceName}', 64) - params: { - name: dataCollectionRulesResourceName + name: dataCollectionRulesResourceName tags: tags enableTelemetry: enableTelemetry location: dataCollectionRulesLocation @@ -477,307 +405,201 @@ module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection- } } -// ========== Private DNS Zones ========== // -var privateDnsZones = [ - 'privatelink.cognitiveservices.azure.com' - 'privatelink.openai.azure.com' - 'privatelink.services.ai.azure.com' - 'privatelink.contentunderstanding.ai.azure.com' - 'privatelink.blob.${environment().suffixes.storage}' - 'privatelink.queue.${environment().suffixes.storage}' - 'privatelink.mongo.cosmos.azure.com' - 'privatelink.azconfig.io' - 'privatelink.azurecr.io' -] - -// DNS Zone Index Constants -var dnsZoneIndex = { - cognitiveServices: 0 - openAI: 1 - aiServices: 2 - contentUnderstanding: 3 - storageBlob: 4 - storageQueue: 5 - cosmosDB: 6 - appConfig: 7 - containerRegistry: 8 -} - -@batchSize(5) -module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ - for (zone, i) in privateDnsZones: if (enablePrivateNetworking) { - name: take('avm.res.network.private-dns-zone.${split(zone, '.')[1]}', 64) - params: { - name: zone - tags: tags - enableTelemetry: enableTelemetry - virtualNetworkLinks: [{ virtualNetworkResourceId: virtualNetwork!.outputs.resourceId }] - } - } -] +// ============================================================================ +// Module: Networking (WAF - conditional) +// ============================================================================ -// ========== Log Analytics & Application Insights ========== // -module logAnalyticsWorkspace './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { - name: take('module.log-analytics-workspace.${solutionSuffix}', 64) +module virtualNetwork './modules/networking/virtual-network.bicep' = if (enablePrivateNetworking) { + name: take('module.virtual-network.${solutionSuffix}', 64) params: { solutionName: solutionSuffix - name: logAnalyticsWorkspaceResourceName + addressPrefixes: ['10.0.0.0/8'] location: location tags: tags + logAnalyticsWorkspaceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + resourceSuffix: solutionSuffix enableTelemetry: enableTelemetry - enableReplication: enableRedundancy - replicationLocation: replicaLocation - } -} - -module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (enableMonitoring) { - name: take('avm.res.insights.component.${solutionSuffix}', 64) - params: { - name: 'appi-${solutionSuffix}' - location: location - enableTelemetry: enableTelemetry - retentionInDays: 365 - kind: 'web' - disableIpMasking: false - flowType: 'Bluefield' - // WAF aligned configuration for Monitoring - workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null - tags: tags } } -@description('Optional. Tag, Created by user name.') -param createdBy string = contains(deployer(), 'userPrincipalName') - ? split(deployer().userPrincipalName, '@')[0] - : deployer().objectId - -// ========== Resource Group Tag ========== // -resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { - name: 'default' - properties: { - tags: { - ...resourceGroup().tags - ...tags - TemplateName: 'Content Processing' - Type: enablePrivateNetworking ? 'WAF' : 'Non-WAF' - CreatedBy: createdBy - DeploymentName: deployment().name - } - } -} - -// ========== Managed Identity ========== // -module avmManagedIdentity './modules/identity/managed-identity.bicep' = { - name: take('module.managed-identity.${solutionSuffix}', 64) +module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePrivateNetworking) { + name: take('avm.res.network.bastion-host.${solutionSuffix}', 64) params: { - solutionName: solutionSuffix - identityName: 'id-${solutionSuffix}' + name: bastionHostName + skuName: 'Standard' location: location + virtualNetworkResourceId: virtualNetwork!.outputs.resourceId + diagnosticSettings: enableMonitoring + ? [ + { + name: 'bastionDiagnostics' + workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + } + ] + : null tags: tags enableTelemetry: enableTelemetry + publicIPAddressObject: { + name: 'pip-${bastionHostName}' + } } } -module avmContainerRegistry './modules/compute/container-registry.bicep' = { - name: take('module.container-registry.${solutionSuffix}', 64) +module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enablePrivateNetworking) { + name: take('avm.res.compute.virtual-machine.${solutionSuffix}', 64) params: { - solutionName: solutionSuffix - name: 'cr${replace(solutionSuffix, '-', '')}' + name: jumpboxVmName location: location - sku: enableRedundancy || enablePrivateNetworking ? 'Premium' : 'Standard' - publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' - acrPullPrincipalIds: [ - avmContainerRegistryReader.outputs.principalId - ] tags: tags enableTelemetry: enableTelemetry - enablePrivateNetworking: enablePrivateNetworking - privateEndpointSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.backendSubnetResourceId : '' - privateDnsZoneResourceIds: enablePrivateNetworking - ? [avmPrivateDnsZones[dnsZoneIndex.containerRegistry]!.outputs.resourceId] - : [] - } -} - -// // ========== Storage Account ========== // -module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { - name: take('module.storage-account.${solutionSuffix}', 64) - params: { - name: 'st${replace(solutionSuffix, '-', '')}' - location: location - managedIdentities: { systemAssigned: true } - minimumTlsVersion: 'TLS1_2' - enableTelemetry: enableTelemetry - roleAssignments: [ - { - principalId: avmManagedIdentity.outputs.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - } - { - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' + computerName: take(jumpboxVmName, 15) + osType: 'Windows' + vmSize: empty(vmSize) ? 'Standard_D2s_v5' : vmSize + adminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername + adminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword + managedIdentities: { + systemAssigned: true + } + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId + enableAutomaticUpdates: true + encryptionAtHost: false + availabilityZone: enableRedundancy ? 1 : -1 + imageReference: { + publisher: 'microsoft-dsvm' + offer: 'dsvm-win-2022' + sku: 'winserver-2022' + version: 'latest' + } + osDisk: { + name: 'osdisk-${jumpboxVmName}' + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + // WAF aligned configuration - use Premium storage for better SLA when redundancy is enabled + storageAccountType: enableRedundancy ? 'Premium_LRS' : 'Standard_LRS' } + } + nicConfigurations: [ { - roleDefinitionIdOrName: 'Storage Queue Data Contributor' - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' + name: 'nic-${jumpboxVmName}' + tags: tags + deleteOption: 'Delete' + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : null + ipConfigurations: [ + { + name: '${jumpboxVmName}-nic01-ipconfig01' + subnetResourceId: virtualNetwork!.outputs.administrationSubnetResourceId + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : null + } + ] } ] - networkAcls: { - bypass: 'AzureServices' - defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' - ipRules: [] + extensionAadJoinConfig: { + enabled: true + tags: tags + typeHandlerVersion: '1.0' + settings: { + mdmId:'' + } } - requireInfrastructureEncryption: true - supportsHttpsTrafficOnly: true - accessTier: 'Hot' - tags: tags - - //<======================= WAF related parameters - allowBlobPublicAccess: false - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - privateEndpoints: (enablePrivateNetworking) - ? [ - { - name: 'pep-blob-${solutionSuffix}' - customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'storage-dns-zone-group-blob' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId - } - ] - } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - service: 'blob' - } - { - name: 'pep-queue-${solutionSuffix}' - customNetworkInterfaceName: 'nic-queue-${solutionSuffix}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'storage-dns-zone-group-queue' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageQueue]!.outputs.resourceId - } - ] + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: tags + } + //WAF aligned configuration for Monitoring + extensionMonitoringAgentConfig: enableMonitoring + ? { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId + name: 'send-${logAnalyticsWorkspace!.outputs.name}' } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - service: 'queue' - } - ] - : [] + ] + enabled: true + tags: tags + } + : null + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: tags + } } } -// // ========== AI Foundry and related resources ========== // -module avmAiServices './modules/ai/ai-foundry.bicep' = { - name: take('module.ai-services.${solutionSuffix}', 64) +module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = if (enablePrivateNetworking) { + name: take('avm.res.maintenance.maintenance-configuration.${solutionSuffix}', 64) params: { - name: 'aif-${solutionSuffix}' - projectName: 'proj-${solutionSuffix}' - projectDescription: 'proj-${solutionSuffix}' - existingFoundryProjectResourceId: existingProjectResourceId - location: azureAiServiceLocation - sku: 'S0' - allowProjectManagement: true - managedIdentities: { systemAssigned: true } - kind: 'AIServices' - tags: { - app: solutionSuffix - location: azureAiServiceLocation + name: 'mc-${jumpboxVmName}' + location: location + tags: tags + enableTelemetry: enableTelemetry + extensionProperties: { + InGuestPatchMode: 'User' } - customSubDomainName: 'aif-${solutionSuffix}' - diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null - roleAssignments: [ - { - principalId: avmManagedIdentity.outputs.principalId - roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Azure AI Developer' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Azure AI Developer' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services User' - principalType: 'ServicePrincipal' + maintenanceScope: 'InGuestPatch' + maintenanceWindow: { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' + } + visibility: 'Custom' + installPatches: { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] } - { - principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'Cognitive Services User' - principalType: 'ServicePrincipal' + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] } - ] - networkAcls: { - bypass: 'AzureServices' - defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' } - disableLocalAuth: true - enableTelemetry: enableTelemetry - deployments: [ - { - name: gptModelName - model: { - format: 'OpenAI' - name: gptModelName - version: gptModelVersion - } - sku: { - name: deploymentType - capacity: gptDeploymentCapacity - } - raiPolicyName: 'Microsoft.Default' - } - ] - - // WAF related parameters - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - //publicNetworkAccess: 'Enabled' // Always enabled for AI Services } } +@batchSize(5) +module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ + for (zone, i) in privateDnsZones: if (enablePrivateNetworking) { + name: take('avm.res.network.private-dns-zone.${solutionSuffix}.${i}', 64) + params: { + name: zone + tags: tags + enableTelemetry: enableTelemetry + virtualNetworkLinks: [{ virtualNetworkResourceId: virtualNetwork!.outputs.resourceId }] + } + } +] + module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking && empty(existingProjectResourceId)) { name: take('avm.res.network.private-endpoint.${solutionSuffix}', 64) params: { @@ -818,11 +640,60 @@ module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoi } } -// ========== Container App Environment ========== // -module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { - name: take('avm.res.app.managed-environment.${solutionSuffix}', 64) +// ============================================================================ +// Module: Identity +// ============================================================================ + +module avmManagedIdentity './modules/identity/managed-identity.bicep' = { + name: take('module.managed-identity.${solutionSuffix}', 64) params: { - name: 'cae-${solutionSuffix}' + solutionName: solutionSuffix + identityName: 'id-${solutionSuffix}' + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +module avmContainerRegistryReader 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { + name: take('avm.res.managed-identity.user-assigned-identity.${solutionSuffix}', 64) + params: { + name: 'id-acr-${solutionSuffix}' + location: location + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Module: Compute (Container Registry, Container App Env, Container Apps) +// ============================================================================ + +module avmContainerRegistry './modules/compute/container-registry.bicep' = { + name: take('module.container-registry.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: 'cr${replace(solutionSuffix, '-', '')}' + location: location + sku: enableRedundancy || enablePrivateNetworking ? 'Premium' : 'Standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + acrPullPrincipalIds: [ + avmContainerRegistryReader.outputs.principalId + ] + tags: tags + enableTelemetry: enableTelemetry + enablePrivateNetworking: enablePrivateNetworking + privateEndpointSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.backendSubnetResourceId : '' + privateDnsZoneResourceIds: enablePrivateNetworking + ? [avmPrivateDnsZones[dnsZoneIndex.containerRegistry]!.outputs.resourceId] + : [] + } +} + +module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { + name: take('avm.res.app.managed-environment.${solutionSuffix}', 64) + params: { + name: 'cae-${solutionSuffix}' location: location tags: { ...resourceGroup().tags @@ -855,18 +726,6 @@ module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { } } -// //=========== Managed Identity for Container Registry ========== // -module avmContainerRegistryReader 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { - name: take('avm.res.managed-identity.user-assigned-identity.${solutionSuffix}', 64) - params: { - name: 'id-acr-${solutionSuffix}' - location: location - tags: tags - enableTelemetry: enableTelemetry - } -} - -// ========== Container App ========== // module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app.${solutionSuffix}', 64) params: { @@ -935,7 +794,6 @@ module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { } } -// ========== Container App API ========== // module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app-api.${solutionSuffix}', 64) params: { @@ -1067,7 +925,6 @@ module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { } } -//========== Container App Web ========== // module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app-web.${solutionSuffix}', 64) params: { @@ -1150,7 +1007,6 @@ module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { } } -// ========== Container App Workflow ========== // module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app-wkfl.${solutionSuffix}', 64) params: { @@ -1217,157 +1073,621 @@ module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { } } -// ========== Cosmos Database for Mongo DB ========== // -module avmCosmosDB 'br/public:avm/res/document-db/database-account:0.19.0' = { - name: take('avm.res.document-db.database-account.${solutionSuffix}', 64) +module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-update.${solutionSuffix}', 64) params: { - name: 'cosmos-${solutionSuffix}' + name: 'ca-${solutionSuffix}-app' location: location - mongodbDatabases: [ - { - name: 'default' - tag: 'default database' - } - ] - tags: tags enableTelemetry: enableTelemetry - databaseAccountOfferType: 'Standard' - enableAutomaticFailover: false - serverVersion: '7.0' - capabilitiesToAdd: [ - 'EnableMongo' - ] - defaultConsistencyLevel: 'Session' - maxIntervalInSeconds: 5 - maxStalenessPrefix: 100 - zoneRedundant: false - - // WAF related parameters - networkRestrictions: { - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - ipRules: [] - virtualNetworkRules: [] + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] } + containers: [ + { + name: 'ca-${solutionSuffix}' + image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - privateEndpoints: (enablePrivateNetworking) - ? [ + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ { - name: 'pep-cosmosdb-${solutionSuffix}' - customNetworkInterfaceName: 'nic-cosmosdb-${solutionSuffix}' - privateEndpointResourceId: virtualNetwork!.outputs.resourceId - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'cosmosdb-dns-zone-group' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId - } - ] - } - service: 'MongoDB' - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' } ] - : [] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: enableScalability + ? [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: 100 + } + } + } + ] + : [] + } } + dependsOn: [ + cognitiveServicePrivateEndpoint + ] } -// ========== AI Search ========== // -module avmAiSearch './modules/ai/ai-search.bicep' = { - name: take('module.ai-search.${solutionSuffix}', 64) +module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) params: { - solutionName: solutionSuffix - name: 'srch-${solutionSuffix}' + name: 'ca-${solutionSuffix}-api' location: location - skuName: 'basic' - replicaCount: enableRedundancy ? 2 : 1 - partitionCount: enableScalability ? 2 : 1 - tags: tags enableTelemetry: enableTelemetry - } -} - -// ========== App Configuration ========== // -module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { - name: take('avm.res.app.configuration-store.${solutionSuffix}', 64) - params: { - name: 'appcs-${solutionSuffix}' - location: location - enablePurgeProtection: enablePurgeProtection - tags: { - app: solutionSuffix - location: location + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] } - enableTelemetry: enableTelemetry - managedIdentities: { systemAssigned: true } - sku: 'Standard' - diagnosticSettings: enableMonitoring - ? [ + + containers: [ + { + name: 'ca-${solutionSuffix}-api' + image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ { - workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' - logCategoriesAndGroups: [ - { - categoryGroup: 'allLogs' - enabled: true - } - ] + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ] + probes: [ + // Liveness Probe - Checks if the app is still running + { + type: 'Liveness' + httpGet: { + path: '/startup' // Your app must expose this endpoint + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + // Readiness Probe - Checks if the app is ready to receive traffic + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 // Wait 10s before checking + periodSeconds: 5 // Check every 15s + failureThreshold: 10 // Restart if it fails 5 times } ] - : null - disableLocalAuth: false - replicaLocations: enableRedundancy? [{ replicaLocation: replicaLocation }] : [] - roleAssignments: [ - { - principalId: avmContainerApp.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' - } - { - principalId: avmContainerApp_API.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' } + ] + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] + } + ingressExternal: true + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + corsPolicy: { + allowedOrigins: [ + '*' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + 'Authorization' + 'Content-Type' + '*' + ] + } + } + dependsOn: [ + cognitiveServicePrivateEndpoint + ] +} + +module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { + name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) + params: { + name: 'ca-${solutionSuffix}-wkfl' + location: location + enableTelemetry: enableTelemetry + environmentResourceId: avmContainerAppEnv.outputs.resourceId + workloadProfileName: 'Consumption' + registries: null + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId + ] + } + containers: [ { - principalId: avmContainerApp_Web.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalType: 'ServicePrincipal' + name: 'ca-${solutionSuffix}-wkfl' + image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: avmAppConfig.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? applicationInsights.outputs.connectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ] } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + } +} + +// ============================================================================ +// Module: AI Services +// ============================================================================ + +module avmAiServices './modules/ai/ai-foundry.bicep' = { + name: take('module.ai-services.${solutionSuffix}', 64) + params: { + name: 'aif-${solutionSuffix}' + projectName: 'proj-${solutionSuffix}' + projectDescription: 'proj-${solutionSuffix}' + existingFoundryProjectResourceId: existingProjectResourceId + location: azureAiServiceLocation + sku: 'S0' + allowProjectManagement: true + managedIdentities: { systemAssigned: true } + kind: 'AIServices' + tags: { + app: solutionSuffix + location: azureAiServiceLocation + } + customSubDomainName: 'aif-${solutionSuffix}' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null + roleAssignments: [ { - principalId: avmContainerApp_Workflow.outputs.?systemAssignedMIPrincipalId! - roleDefinitionIdOrName: 'App Configuration Data Reader' + principalId: avmManagedIdentity.outputs.principalId + roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role principalType: 'ServicePrincipal' } - ] - keyValues: [ { - name: 'APP_AZURE_OPENAI_ENDPOINT' - value: avmAiServices.outputs.endpoint //TODO: replace with actual endpoint + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' } { - name: 'APP_AZURE_OPENAI_MODEL' - value: gptModelName + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' } { - name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' - value: avmAiServices.outputs.endpoint + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' } { - name: 'APP_COSMOS_CONTAINER_PROCESS' - value: 'Processes' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' } { - name: 'APP_COSMOS_CONTAINER_SCHEMA' - value: 'Schemas' + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' } { - name: 'APP_COSMOS_DATABASE' - value: 'ContentProcess' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' + } + disableLocalAuth: true + enableTelemetry: enableTelemetry + deployments: [ { - name: 'APP_CPS_CONFIGURATION' - value: 'cps-configuration' + name: gptModelName + model: { + format: 'OpenAI' + name: gptModelName + version: gptModelVersion + } + sku: { + name: deploymentType + capacity: gptDeploymentCapacity + } + raiPolicyName: 'Microsoft.Default' } + ] + + // WAF related parameters + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + //publicNetworkAccess: 'Enabled' // Always enabled for AI Services + } +} + +module avmAiSearch './modules/ai/ai-search.bicep' = { + name: take('module.ai-search.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: 'srch-${solutionSuffix}' + location: location + skuName: 'basic' + replicaCount: enableRedundancy ? 2 : 1 + partitionCount: enableScalability ? 2 : 1 + tags: tags + enableTelemetry: enableTelemetry + } +} + +// ============================================================================ +// Module: Data (Storage, Cosmos DB, App Configuration) +// ============================================================================ + +module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { + name: take('avm.res.storage.storage-account.${solutionSuffix}', 64) + params: { + name: 'st${replace(solutionSuffix, '-', '')}' + location: location + managedIdentities: { systemAssigned: true } + minimumTlsVersion: 'TLS1_2' + enableTelemetry: enableTelemetry + roleAssignments: [ { - name: 'APP_CPS_MAX_FILESIZE_MB' + principalId: avmManagedIdentity.outputs.principalId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp_API.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Storage Queue Data Contributor' + principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: (enablePrivateNetworking) ? 'Deny' : 'Allow' + ipRules: [] + } + requireInfrastructureEncryption: true + supportsHttpsTrafficOnly: true + accessTier: 'Hot' + tags: tags + + //<======================= WAF related parameters + allowBlobPublicAccess: false + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + privateEndpoints: (enablePrivateNetworking) + ? [ + { + name: 'pep-blob-${solutionSuffix}' + customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'storage-dns-zone-group-blob' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + service: 'blob' + } + { + name: 'pep-queue-${solutionSuffix}' + customNetworkInterfaceName: 'nic-queue-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'storage-dns-zone-group-queue' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageQueue]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + service: 'queue' + } + ] + : [] + } +} + +module avmCosmosDB 'br/public:avm/res/document-db/database-account:0.19.0' = { + name: take('avm.res.document-db.database-account.${solutionSuffix}', 64) + params: { + name: 'cosmos-${solutionSuffix}' + location: location + mongodbDatabases: [ + { + name: 'default' + tag: 'default database' + } + ] + tags: tags + enableTelemetry: enableTelemetry + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + serverVersion: '7.0' + capabilitiesToAdd: [ + 'EnableMongo' + ] + defaultConsistencyLevel: 'Session' + maxIntervalInSeconds: 5 + maxStalenessPrefix: 100 + zoneRedundant: false + + // WAF related parameters + networkRestrictions: { + publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' + ipRules: [] + virtualNetworkRules: [] + } + + privateEndpoints: (enablePrivateNetworking) + ? [ + { + name: 'pep-cosmosdb-${solutionSuffix}' + customNetworkInterfaceName: 'nic-cosmosdb-${solutionSuffix}' + privateEndpointResourceId: virtualNetwork!.outputs.resourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'cosmosdb-dns-zone-group' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId + } + ] + } + service: 'MongoDB' + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + } + ] + : [] + } +} + +module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { + name: take('avm.res.app-configuration.configuration-store.${solutionSuffix}', 64) + params: { + name: 'appcs-${solutionSuffix}' + location: location + enablePurgeProtection: enablePurgeProtection + tags: { + app: solutionSuffix + location: location + } + enableTelemetry: enableTelemetry + managedIdentities: { systemAssigned: true } + sku: 'Standard' + diagnosticSettings: enableMonitoring + ? [ + { + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + } + ] + : null + disableLocalAuth: false + replicaLocations: enableRedundancy? [{ replicaLocation: replicaLocation }] : [] + roleAssignments: [ + { + principalId: avmContainerApp.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_API.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Web.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: avmContainerApp_Workflow.outputs.?systemAssignedMIPrincipalId! + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalType: 'ServicePrincipal' + } + ] + keyValues: [ + { + name: 'APP_AZURE_OPENAI_ENDPOINT' + value: avmAiServices.outputs.endpoint //TODO: replace with actual endpoint + } + { + name: 'APP_AZURE_OPENAI_MODEL' + value: gptModelName + } + { + name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' + value: avmAiServices.outputs.endpoint + } + { + name: 'APP_COSMOS_CONTAINER_PROCESS' + value: 'Processes' + } + { + name: 'APP_COSMOS_CONTAINER_SCHEMA' + value: 'Schemas' + } + { + name: 'APP_COSMOS_DATABASE' + value: 'ContentProcess' + } + { + name: 'APP_CPS_CONFIGURATION' + value: 'cps-configuration' + } + { + name: 'APP_CPS_MAX_FILESIZE_MB' value: '20' } { @@ -1513,7 +1833,7 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 } module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = if (enablePrivateNetworking) { - name: take('avm.res.app.configuration-store.update.${solutionSuffix}', 64) + name: take('avm.res.app-configuration.configuration-store.update.${solutionSuffix}', 64) params: { name: 'appcs-${solutionSuffix}' location: location @@ -1543,294 +1863,16 @@ module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-st ] } -// ========== Container App Update Modules ========== // -module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-update.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-app' - location: location - enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' +// ============================================================================ +// Module: Role Assignments +// ============================================================================ - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessor' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: enableScalability - ? [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: 100 - } - } - } - ] - : [] - } - } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] -} - -module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-api' - location: location - enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - - containers: [ - { - name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorAPI' - } - ] - probes: [ - // Liveness Probe - Checks if the app is still running - { - type: 'Liveness' - httpGet: { - path: '/startup' // Your app must expose this endpoint - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - // Readiness Probe - Checks if the app is ready to receive traffic - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 // Wait 10s before checking - periodSeconds: 5 // Check every 15s - failureThreshold: 10 // Restart if it fails 5 times - } - ] - } - ] - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - ingressExternal: true - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - corsPolicy: { - allowedOrigins: [ - '*' - ] - allowedMethods: [ - 'GET' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - ] - allowedHeaders: [ - 'Authorization' - 'Content-Type' - '*' - ] - } - } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] -} - -// ========== Container App Workflow Update ========== // -module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) - params: { - name: 'ca-${solutionSuffix}-wkfl' - location: location - enableTelemetry: enableTelemetry - environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null - tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorWorkflow' - } - ] - } - ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } - } -} +// Access control is configured inline through module roleAssignments and +// principal assignment parameters to preserve existing deployment behavior. -// ============ // -// Outputs // -// ============ // +// ============================================================================ +// Outputs +// ============================================================================ @description('The name of the Container App used for Web App.') output CONTAINER_WEB_APP_NAME string = avmContainerApp_Web.outputs.name diff --git a/infra/bicep/main.bicep b/infra/bicep/main.bicep index 3a3b9f19..9d5bf754 100644 --- a/infra/bicep/main.bicep +++ b/infra/bicep/main.bicep @@ -1,34 +1,136 @@ +// ============================================================================ +// Main Deployment Template +// ============================================================================ + targetScope = 'resourceGroup' metadata name = 'Content Processing Solution Accelerator - Bicep' metadata description = 'Deploys Content Processing resources using the restored private-repo module interfaces.' +// ============================================================================ +// Parameters — Core +// ============================================================================ + @minLength(3) @maxLength(20) +@description('Optional. Name of the solution to deploy. This should be 3-20 characters long.') param solutionName string = 'cps' +@maxLength(5) +@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources.') +param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) + @metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for all services.') param location string -@metadata({ azd: { type: 'location' } }) +@description('Optional. Tags to be applied to the resources.') +param tags object = { + app: 'Content Processing Solution Accelerator' + location: resourceGroup().location +} + +@minLength(1) +@allowed([ + 'australiaeast' + 'eastus' + 'eastus2' + 'japaneast' + 'southcentralus' + 'southeastasia' + 'swedencentral' + 'uksouth' + 'westeurope' + 'westus' + 'westus3' +]) +@description('Required. Location for the Azure AI Services deployment.') +@metadata({ + azd: { + type: 'location' + usageName: [ + 'OpenAI.GlobalStandard.gpt-5.1,300' + ] + } +}) param azureAiServiceLocation string +// ============================================================================ +// Parameters — AI Configuration +// ============================================================================ + +@description('Optional. Type of GPT deployment to use: Standard | GlobalStandard.') +@allowed([ + 'Standard' + 'GlobalStandard' +]) +param deploymentType string = 'GlobalStandard' + +@description('Optional. Name of the GPT model to deploy.') param gptModelName string = 'gpt-5.1' + +@description('Optional. Version of the GPT model to deploy. Empty string uses the latest available version.') +param gptModelVersion string = '' + +@minValue(1) +@description('Optional. Capacity of the GPT deployment.') +param gptDeploymentCapacity int = 10 + +// ============================================================================ +// Parameters — Compute +// ============================================================================ + +@description('Optional. The container registry login server or endpoint for the container images.') param containerRegistryEndpoint string = '' + +@description('Optional. The image tag for the container images.') param imageTag string = 'latest_v2' + +// ============================================================================ +// Parameters — WAF Feature Flags +// ============================================================================ + +@description('Optional. Enable private networking for the deployment.') param enablePrivateNetworking bool = false + +@description('Optional. Enable monitoring applicable resources.') param enableMonitoring bool = false + +@description('Optional. Enable redundancy for applicable resources.') param enableRedundancy bool = false + +@description('Optional. Enable scalability for applicable resources.') param enableScalability bool = false + +@description('Optional. Enable or disable usage telemetry for the deployment.') param enableTelemetry bool = true + +@description('Optional. Enable purge protection.') param enablePurgeProtection bool = false -param tags object = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} -var uniqueToken = substring(uniqueString(subscription().subscriptionId, resourceGroup().id, solutionName), 0, 5) -var solutionSuffix = toLower(replace(replace(replace('${solutionName}${uniqueToken}', '-', ''), '_', ''), '.', '')) +// ============================================================================ +// Parameters — Existing Resources +// ============================================================================ + +@description('Optional. Existing Log Analytics Workspace resource ID.') +param existingLogAnalyticsWorkspaceId string = '' + +@description('Optional. Existing Azure AI Foundry project resource ID.') +param existingFoundryProjectResourceId string = '' + +// ============================================================================ +// Variables +// ============================================================================ + +var solutionSuffix = toLower(trim(replace( + replace( + replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), + ' ', + '' + ), + '*', + '' +))) var managedIdentityName = 'id-${solutionSuffix}' var containerRegistryName = replace('cr${solutionSuffix}', '-', '') @@ -57,6 +159,146 @@ var cognitiveServicesOpenAiUserRoleId = subscriptionResourceId('Microsoft.Author var cognitiveServicesUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908') var azureAiDeveloperRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee') +var effectiveContainerRegistryEndpoint = empty(containerRegistryEndpoint) ? containerRegistry.outputs.loginServer : containerRegistryEndpoint +var apiAppFqdn = '${contentProcessorApiName}.${containerAppEnvironment.outputs.defaultDomain}' +var webAppFqdn = '${contentProcessorWebName}.${containerAppEnvironment.outputs.defaultDomain}' +var workflowAppFqdn = '${contentProcessorWorkflowName}.${containerAppEnvironment.outputs.defaultDomain}' +var cosmosDbEndpoint = 'https://${cosmosDb.name}.mongo.cosmos.azure.com:443/' + +var sharedEnv = [ + { + name: 'APP_CONFIG_ENDPOINT' + value: appConfiguration.outputs.endpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? appInsights!.outputs.connectionString : '' + } +] + +var apiProbes = [ + { + type: 'Liveness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 + periodSeconds: 5 + failureThreshold: 10 + } +] + +var appConfigurationValues = [ + { + name: 'APP_AZURE_OPENAI_ENDPOINT' + value: aiFoundry.outputs.endpoint + } + { + name: 'APP_AZURE_OPENAI_MODEL' + value: gptModelName + } + { + name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' + value: aiFoundry.outputs.endpoint + } + { + name: 'APP_AI_PROJECT_ENDPOINT' + value: aiProject.properties.endpoints['AI Foundry API'] + } + { + name: 'APP_COSMOS_DB_ENDPOINT' + value: cosmosDbEndpoint + } + { + name: 'APP_COSMOS_DB_NAME' + value: cosmosDatabaseName + } + { + name: 'APP_COSMOS_DB_CONTAINER' + value: cosmosContainerName + } + { + name: 'APP_STORAGE_ACCOUNT_NAME' + value: storageAccount.outputs.name + } + { + name: 'APP_STORAGE_BLOB_ENDPOINT' + value: storageAccount.outputs.blobEndpoint + } + { + name: 'APP_STORAGE_QUEUE_ENDPOINT' + value: storageAccount.outputs.serviceEndpoints.queue + } + { + name: 'APP_STORAGE_CONTAINER_NAME' + value: storageContainerName + } + { + name: 'APP_AI_SEARCH_ENDPOINT' + value: aiSearch.outputs.endpoint + } + { + name: 'APP_AI_SEARCH_INDEX' + value: 'content-index' + } + { + name: 'APP_WORKFLOW_APP_ENDPOINT' + value: 'https://${workflowAppFqdn}' + } + { + name: 'APP_API_ENDPOINT' + value: 'https://${apiAppFqdn}' + } + { + name: 'AZURE_OPENAI_API_VERSION' + value: '2025-03-01-preview' + } + { + name: 'AZURE_TRACING_ENABLED' + value: 'True' + } +] + +// ============================================================================ +// Module — Monitoring — Log Analytics +// ============================================================================ + module logAnalytics './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { name: take('module.log-analytics.${solutionSuffix}', 64) params: { @@ -66,6 +308,10 @@ module logAnalytics './modules/monitoring/log-analytics.bicep' = if (enableMonit } } +// ============================================================================ +// Module — Monitoring — Application Insights +// ============================================================================ + module appInsights './modules/monitoring/app-insights.bicep' = if (enableMonitoring) { name: take('module.app-insights.${solutionSuffix}', 64) params: { @@ -76,6 +322,10 @@ module appInsights './modules/monitoring/app-insights.bicep' = if (enableMonitor } } +// ============================================================================ +// Module — Identity — Managed Identity +// ============================================================================ + module managedIdentity './modules/identity/managed-identity.bicep' = { name: take('module.managed-identity.${solutionSuffix}', 64) params: { @@ -86,6 +336,10 @@ module managedIdentity './modules/identity/managed-identity.bicep' = { } } +// ============================================================================ +// Module — Compute — Container Registry +// ============================================================================ + module containerRegistry './modules/compute/container-registry.bicep' = { name: take('module.container-registry.${solutionSuffix}', 64) params: { @@ -98,6 +352,10 @@ module containerRegistry './modules/compute/container-registry.bicep' = { } } +// ============================================================================ +// Module — Data — Storage Account +// ============================================================================ + module storageAccount './modules/data/storage-account.bicep' = { name: take('module.storage-account.${solutionSuffix}', 64) params: { @@ -115,6 +373,10 @@ module storageAccount './modules/data/storage-account.bicep' = { } } +// ============================================================================ +// Resources — Storage Queue +// ============================================================================ + resource storageAccountResource 'Microsoft.Storage/storageAccounts@2025-08-01' existing = { name: storageAccountName } @@ -129,6 +391,10 @@ resource storageQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@20 name: storageQueueName } +// ============================================================================ +// Resources — Cosmos DB +// ============================================================================ + resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { name: cosmosDbName location: location @@ -192,6 +458,10 @@ resource cosmosMongoCollection 'Microsoft.DocumentDB/databaseAccounts/mongodbDat } } +// ============================================================================ +// Module — AI — AI Foundry +// ============================================================================ + module aiFoundry './modules/ai/ai-foundry.bicep' = { name: take('module.ai-foundry.${solutionSuffix}', 64) params: { @@ -205,6 +475,10 @@ module aiFoundry './modules/ai/ai-foundry.bicep' = { } } +// ============================================================================ +// Resources — AI Project +// ============================================================================ + resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { name: aiServicesName } @@ -223,17 +497,26 @@ resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = properties: {} } +// ============================================================================ +// Module — AI — Model Deployment +// ============================================================================ + module modelDeployment './modules/ai/ai-foundry-model-deployment.bicep' = { - name: take('module.ai-model.${solutionSuffix}', 64) + name: take('module.model-deployment.${solutionSuffix}', 64) params: { aiServicesAccountName: aiFoundry.outputs.name deploymentName: modelDeploymentName modelName: gptModelName - skuName: 'GlobalStandard' - skuCapacity: 10 + modelVersion: gptModelVersion + skuName: deploymentType + skuCapacity: gptDeploymentCapacity } } +// ============================================================================ +// Module — AI — Search +// ============================================================================ + module aiSearch './modules/ai/ai-search.bicep' = { name: take('module.ai-search.${solutionSuffix}', 64) params: { @@ -247,6 +530,10 @@ module aiSearch './modules/ai/ai-search.bicep' = { } } +// ============================================================================ +// Module — Compute — Container App Environment +// ============================================================================ + module containerAppEnvironment './modules/compute/container-app-environment.bicep' = { name: take('module.container-app-environment.${solutionSuffix}', 64) params: { @@ -259,144 +546,12 @@ module containerAppEnvironment './modules/compute/container-app-environment.bice } } -var effectiveContainerRegistryEndpoint = empty(containerRegistryEndpoint) ? containerRegistry.outputs.loginServer : containerRegistryEndpoint -var apiAppFqdn = '${contentProcessorApiName}.${containerAppEnvironment.outputs.defaultDomain}' -var webAppFqdn = '${contentProcessorWebName}.${containerAppEnvironment.outputs.defaultDomain}' -var workflowAppFqdn = '${contentProcessorWorkflowName}.${containerAppEnvironment.outputs.defaultDomain}' -var cosmosDbEndpoint = 'https://${cosmosDb.name}.mongo.cosmos.azure.com:443/' - -var sharedEnv = [ - { - name: 'APP_CONFIG_ENDPOINT' - value: appConfiguration.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? appInsights!.outputs.connectionString : '' - } -] - -var apiProbes = [ - { - type: 'Liveness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 - periodSeconds: 5 - failureThreshold: 10 - } -] - -var appConfigurationValues = [ - { - name: 'APP_AZURE_OPENAI_ENDPOINT' - value: aiFoundry.outputs.endpoint - } - { - name: 'APP_AZURE_OPENAI_MODEL' - value: gptModelName - } - { - name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' - value: aiFoundry.outputs.endpoint - } - { - name: 'APP_AI_PROJECT_ENDPOINT' - value: aiProject.properties.endpoints['AI Foundry API'] - } - { - name: 'APP_COSMOS_DB_ENDPOINT' - value: cosmosDbEndpoint - } - { - name: 'APP_COSMOS_DB_NAME' - value: cosmosDatabaseName - } - { - name: 'APP_COSMOS_DB_CONTAINER' - value: cosmosContainerName - } - { - name: 'APP_STORAGE_ACCOUNT_NAME' - value: storageAccount.outputs.name - } - { - name: 'APP_STORAGE_BLOB_ENDPOINT' - value: storageAccount.outputs.blobEndpoint - } - { - name: 'APP_STORAGE_QUEUE_ENDPOINT' - value: storageAccount.outputs.serviceEndpoints.queue - } - { - name: 'APP_STORAGE_CONTAINER_NAME' - value: storageContainerName - } - { - name: 'APP_AI_SEARCH_ENDPOINT' - value: aiSearch.outputs.endpoint - } - { - name: 'APP_AI_SEARCH_INDEX' - value: 'content-index' - } - { - name: 'APP_WORKFLOW_APP_ENDPOINT' - value: 'https://${workflowAppFqdn}' - } - { - name: 'APP_API_ENDPOINT' - value: 'https://${apiAppFqdn}' - } - { - name: 'AZURE_OPENAI_API_VERSION' - value: '2025-03-01-preview' - } - { - name: 'AZURE_TRACING_ENABLED' - value: 'True' - } -] +// ============================================================================ +// Module — Data — App Configuration +// ============================================================================ module appConfiguration './modules/data/app-configuration.bicep' = { - name: take('module.app-config.${solutionSuffix}', 64) + name: take('module.app-configuration.${solutionSuffix}', 64) params: { solutionName: solutionSuffix name: appConfigurationName @@ -406,8 +561,12 @@ module appConfiguration './modules/data/app-configuration.bicep' = { } } +// ============================================================================ +// Module — Compute — Content Processor App +// ============================================================================ + module contentProcessorApp './modules/compute/container-app.bicep' = { - name: take('module.content-app.${solutionSuffix}', 64) + name: take('module.content-processor-app.${solutionSuffix}', 64) params: { name: contentProcessorAppName location: location @@ -449,8 +608,12 @@ module contentProcessorApp './modules/compute/container-app.bicep' = { } } +// ============================================================================ +// Module — Compute — Content Processor API +// ============================================================================ + module contentProcessorApi './modules/compute/container-app.bicep' = { - name: take('module.content-api.${solutionSuffix}', 64) + name: take('module.content-processor-api.${solutionSuffix}', 64) params: { name: contentProcessorApiName location: location @@ -494,8 +657,12 @@ module contentProcessorApi './modules/compute/container-app.bicep' = { } } +// ============================================================================ +// Module — Compute — Content Processor Web +// ============================================================================ + module contentProcessorWeb './modules/compute/container-app.bicep' = { - name: take('module.content-web.${solutionSuffix}', 64) + name: take('module.content-processor-web.${solutionSuffix}', 64) params: { name: contentProcessorWebName location: location @@ -557,8 +724,12 @@ module contentProcessorWeb './modules/compute/container-app.bicep' = { } } +// ============================================================================ +// Module — Compute — Content Processor Workflow +// ============================================================================ + module contentProcessorWorkflow './modules/compute/container-app.bicep' = { - name: take('module.content-workflow.${solutionSuffix}', 64) + name: take('module.content-processor-workflow.${solutionSuffix}', 64) params: { name: contentProcessorWorkflowName location: location @@ -601,6 +772,10 @@ module contentProcessorWorkflow './modules/compute/container-app.bicep' = { } } +// ============================================================================ +// Resources — Existing Resource References +// ============================================================================ + resource containerRegistryResource 'Microsoft.ContainerRegistry/registries@2025-04-01' existing = { name: containerRegistryName } @@ -609,6 +784,10 @@ resource appConfigurationResource 'Microsoft.AppConfiguration/configurationStore name: appConfigurationName } +// ============================================================================ +// Resources — Role Assignments +// ============================================================================ + resource acrPullAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid(containerRegistryName, managedIdentityName, 'acr-pull') scope: containerRegistryResource @@ -779,6 +958,10 @@ resource contentProcessorWorkflowAiUserAssignment 'Microsoft.Authorization/roleA } } +// ============================================================================ +// Outputs +// ============================================================================ + output SOLUTION_NAME string = solutionName output CONTAINER_WEB_APP_NAME string = contentProcessorWeb.outputs.name output CONTAINER_API_APP_NAME string = contentProcessorApi.outputs.name From cd7ab916784c80ea83e88b433411147ce795911e Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Thu, 11 Jun 2026 12:46:01 +0530 Subject: [PATCH 7/8] refactor(infra): use local cosmos-db-mongo module wrapper in both main.bicep files Refactored Cosmos DB deployment to follow GSA pattern of calling local wrapper modules instead of direct AVM registry calls or inline resources: - avm/main.bicep: replaced direct br/public:avm/res/document-db/... call with ./modules/data/cosmos-db-mongo.bicep - bicep/main.bicep: replaced inline resource definitions with ./modules/data/cosmos-db-mongo.bicep module call - Added primaryReadWriteConnectionString output to AVM wrapper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- infra/avm/main.bicep | 58 ++++----------- infra/avm/modules/data/cosmos-db-mongo.bicep | 3 + infra/bicep/main.bicep | 74 +++++--------------- 3 files changed, 35 insertions(+), 100 deletions(-) diff --git a/infra/avm/main.bicep b/infra/avm/main.bicep index 4a5c81b8..0f1d4fca 100644 --- a/infra/avm/main.bicep +++ b/infra/avm/main.bicep @@ -1554,56 +1554,26 @@ module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { } } -module avmCosmosDB 'br/public:avm/res/document-db/database-account:0.19.0' = { - name: take('avm.res.document-db.database-account.${solutionSuffix}', 64) +module avmCosmosDB './modules/data/cosmos-db-mongo.bicep' = { + name: take('module.cosmos-db-mongo.${solutionSuffix}', 64) params: { + solutionName: solutionSuffix name: 'cosmos-${solutionSuffix}' location: location - mongodbDatabases: [ - { - name: 'default' - tag: 'default database' - } - ] tags: tags enableTelemetry: enableTelemetry - databaseAccountOfferType: 'Standard' - enableAutomaticFailover: false + databaseName: 'default' + collections: [] serverVersion: '7.0' - capabilitiesToAdd: [ - 'EnableMongo' - ] - defaultConsistencyLevel: 'Session' - maxIntervalInSeconds: 5 - maxStalenessPrefix: 100 - zoneRedundant: false - - // WAF related parameters - networkRestrictions: { - publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' - ipRules: [] - virtualNetworkRules: [] - } - - privateEndpoints: (enablePrivateNetworking) - ? [ - { - name: 'pep-cosmosdb-${solutionSuffix}' - customNetworkInterfaceName: 'nic-cosmosdb-${solutionSuffix}' - privateEndpointResourceId: virtualNetwork!.outputs.resourceId - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - name: 'cosmosdb-dns-zone-group' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId - } - ] - } - service: 'MongoDB' - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet - } - ] - : [] + consistencyLevel: 'Session' + zoneRedundant: enableRedundancy + enableAutomaticFailover: enableRedundancy + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + enablePrivateNetworking: enablePrivateNetworking + privateEndpointSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.backendSubnetResourceId : '' + privateDnsZoneResourceIds: enablePrivateNetworking ? [ + avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId + ] : [] } } diff --git a/infra/avm/modules/data/cosmos-db-mongo.bicep b/infra/avm/modules/data/cosmos-db-mongo.bicep index 36baef6c..8089d989 100644 --- a/infra/avm/modules/data/cosmos-db-mongo.bicep +++ b/infra/avm/modules/data/cosmos-db-mongo.bicep @@ -130,6 +130,9 @@ output name string = cosmosAccount.outputs.name @description('MongoDB connection string (without credentials — use Key Vault for secrets).') output connectionString string = 'mongodb+srv://${name}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000' +@description('Primary read-write connection string from the Cosmos DB account.') +output primaryReadWriteConnectionString string = cosmosAccount.outputs.primaryReadWriteConnectionString + @description('Endpoint of the Cosmos DB account.') output endpoint string = 'https://${name}.mongo.cosmos.azure.com:443/' diff --git a/infra/bicep/main.bicep b/infra/bicep/main.bicep index 9d5bf754..6a3a3e3c 100644 --- a/infra/bicep/main.bicep +++ b/infra/bicep/main.bicep @@ -163,7 +163,7 @@ var effectiveContainerRegistryEndpoint = empty(containerRegistryEndpoint) ? cont var apiAppFqdn = '${contentProcessorApiName}.${containerAppEnvironment.outputs.defaultDomain}' var webAppFqdn = '${contentProcessorWebName}.${containerAppEnvironment.outputs.defaultDomain}' var workflowAppFqdn = '${contentProcessorWorkflowName}.${containerAppEnvironment.outputs.defaultDomain}' -var cosmosDbEndpoint = 'https://${cosmosDb.name}.mongo.cosmos.azure.com:443/' +var cosmosDbEndpoint = cosmosDBModule.outputs.endpoint var sharedEnv = [ { @@ -395,69 +395,31 @@ resource storageQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@20 // Resources — Cosmos DB // ============================================================================ -resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { - name: cosmosDbName - location: location - kind: 'MongoDB' - tags: tags - properties: { - databaseAccountOfferType: 'Standard' - locations: [ - { - locationName: location - failoverPriority: 0 - isZoneRedundant: enableRedundancy - } - ] - capabilities: [ +module cosmosDBModule './modules/data/cosmos-db-mongo.bicep' = { + name: take('module.cosmos-db-mongo.${solutionSuffix}', 64) + params: { + solutionName: solutionSuffix + name: cosmosDbName + location: location + tags: tags + databaseName: cosmosDatabaseName + collections: [ { - name: 'EnableMongo' + name: cosmosContainerName + shardKey: { id: 'Hash' } + indexes: [ + { key: { keys: ['_id'] } } + ] } ] - apiProperties: { - serverVersion: '7.0' - } - disableLocalAuth: false + serverVersion: '7.0' + consistencyLevel: 'Session' + zoneRedundant: enableRedundancy enableAutomaticFailover: false - enableMultipleWriteLocations: false publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' } } -resource cosmosMongoDatabase 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2023-04-15' = { - parent: cosmosDb - name: cosmosDatabaseName - properties: { - resource: { - id: cosmosDatabaseName - } - options: {} - } -} - -resource cosmosMongoCollection 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2023-04-15' = { - parent: cosmosMongoDatabase - name: cosmosContainerName - properties: { - resource: { - id: cosmosContainerName - shardKey: { - id: 'Hash' - } - indexes: [ - { - key: { - keys: [ - '_id' - ] - } - } - ] - } - options: {} - } -} - // ============================================================================ // Module — AI — AI Foundry // ============================================================================ From 671c91b311ed6321df0ecd59c2d2854eb691cae8 Mon Sep 17 00:00:00 2001 From: Dhanushree-Microsoft Date: Tue, 16 Jun 2026 18:19:47 +0530 Subject: [PATCH 8/8] [Infra] Refactor code structure for improved readability and maintainability --- infra/avm/main.bicep | 739 +- infra/avm/main.json | 122649 +++++++------- .../modules/ai/ai-foundry-connection.bicep | 4 + infra/avm/modules/ai/ai-foundry-project.bicep | 17 +- infra/avm/modules/ai/ai-foundry.bicep | 94 +- .../modules/ai/existing-project-setup.bicep | 41 +- .../modules/compute/container-app-api.bicep | 177 + .../compute/container-app-environment.bicep | 106 +- .../compute/container-app-processor.bicep | 131 + .../modules/compute/container-app-web.bicep | 123 + .../compute/container-app-workflow.bicep | 113 + infra/avm/modules/compute/container-app.bicep | 123 +- .../compute/maintenance-configuration.bicep | 57 +- .../avm/modules/compute/virtual-machine.bicep | 163 +- .../avm/modules/data/app-configuration.bicep | 106 +- infra/avm/modules/data/storage-account.bicep | 139 +- .../modules/identity/role-assignments.bicep | 80 +- .../avm/modules/monitoring/app-insights.bicep | 66 +- .../monitoring/data-collection-rule.bicep | 128 +- infra/avm/modules/monitoring/workbook.bicep | 56 + .../avm/modules/networking/bastion-host.bicep | 72 +- .../modules/networking/private-dns-zone.bicep | 13 +- .../modules/networking/private-endpoint.bicep | 23 +- infra/bicep/main.bicep | 586 +- infra/bicep/main.json | 2397 +- .../modules/ai/ai-foundry-connection.bicep | 4 + .../bicep/modules/ai/ai-foundry-project.bicep | 6 + infra/bicep/modules/ai/ai-foundry.bicep | 29 +- .../bicep/modules/ai/ai-search-identity.bicep | 8 + infra/bicep/modules/ai/ai-search.bicep | 8 + .../modules/ai/existing-project-setup.bicep | 39 +- infra/bicep/modules/compute/app-service.bicep | 27 + .../compute/container-app-environment.bicep | 9 + .../modules/compute/container-registry.bicep | 16 - infra/bicep/modules/compute/kubernetes.bicep | 6 + .../modules/data/app-configuration.bicep | 2 +- .../bicep/modules/data/storage-account.bicep | 20 + .../modules/identity/role-assignments.bicep | 361 +- .../modules/monitoring/app-insights.bicep | 5 +- infra/bicep/modules/monitoring/workbook.bicep | 56 + infra/main.bicep | 158 +- infra/main.json | 124435 ++++++++------- 42 files changed, 131518 insertions(+), 121874 deletions(-) create mode 100644 infra/avm/modules/compute/container-app-api.bicep create mode 100644 infra/avm/modules/compute/container-app-processor.bicep create mode 100644 infra/avm/modules/compute/container-app-web.bicep create mode 100644 infra/avm/modules/compute/container-app-workflow.bicep create mode 100644 infra/avm/modules/monitoring/workbook.bicep create mode 100644 infra/bicep/modules/monitoring/workbook.bicep diff --git a/infra/avm/main.bicep b/infra/avm/main.bicep index 0f1d4fca..02590023 100644 --- a/infra/avm/main.bicep +++ b/infra/avm/main.bicep @@ -275,8 +275,8 @@ module logAnalyticsWorkspace './modules/monitoring/log-analytics.bicep' = if (en } } -module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (enableMonitoring) { - name: take('avm.res.insights.component.${solutionSuffix}', 64) +module applicationInsights './modules/monitoring/app-insights.bicep' = if (enableMonitoring) { + name: take('module.app-insights.${solutionSuffix}', 64) params: { name: 'appi-${solutionSuffix}' location: location @@ -292,8 +292,8 @@ module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (en } } -module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.11.0' = if (enablePrivateNetworking && enableMonitoring) { - name: take('avm.res.insights.data-collection-rule.${solutionSuffix}', 64) +module windowsVmDataCollectionRules './modules/monitoring/data-collection-rule.bicep' = if (enablePrivateNetworking && enableMonitoring) { + name: take('module.data-collection-rule.${solutionSuffix}', 64) params: { name: dataCollectionRulesResourceName tags: tags @@ -422,8 +422,8 @@ module virtualNetwork './modules/networking/virtual-network.bicep' = if (enableP } } -module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePrivateNetworking) { - name: take('avm.res.network.bastion-host.${solutionSuffix}', 64) +module bastionHost './modules/networking/bastion-host.bicep' = if (enablePrivateNetworking) { + name: take('module.bastion-host.${solutionSuffix}', 64) params: { name: bastionHostName skuName: 'Standard' @@ -451,8 +451,8 @@ module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = if (enablePr } } -module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enablePrivateNetworking) { - name: take('avm.res.compute.virtual-machine.${solutionSuffix}', 64) +module jumpboxVM './modules/compute/virtual-machine.bicep' = if (enablePrivateNetworking) { + name: take('module.virtual-machine.${solutionSuffix}', 64) params: { name: jumpboxVmName location: location @@ -484,7 +484,7 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enable createOption: 'FromImage' deleteOption: 'Delete' diskSizeGB: 128 - managedDisk: { + managedDisk: { // WAF aligned configuration - use Premium storage for better SLA when redundancy is enabled storageAccountType: enableRedundancy ? 'Premium_LRS' : 'Standard_LRS' } @@ -494,14 +494,14 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enable name: 'nic-${jumpboxVmName}' tags: tags deleteOption: 'Delete' - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null ipConfigurations: [ { name: '${jumpboxVmName}-nic01-ipconfig01' subnetResourceId: virtualNetwork!.outputs.administrationSubnetResourceId - diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null } @@ -531,7 +531,6 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enable } tags: tags } - //WAF aligned configuration for Monitoring extensionMonitoringAgentConfig: enableMonitoring ? { dataCollectionRuleAssociations: [ @@ -551,8 +550,8 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.22.0' = if (enable } } -module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = if (enablePrivateNetworking) { - name: take('avm.res.maintenance.maintenance-configuration.${solutionSuffix}', 64) +module maintenanceConfiguration './modules/compute/maintenance-configuration.bicep' = if (enablePrivateNetworking) { + name: take('module.maintenance-configuration.${solutionSuffix}', 64) params: { name: 'mc-${jumpboxVmName}' location: location @@ -588,9 +587,9 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi } @batchSize(5) -module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ +module avmPrivateDnsZones './modules/networking/private-dns-zone.bicep' = [ for (zone, i) in privateDnsZones: if (enablePrivateNetworking) { - name: take('avm.res.network.private-dns-zone.${solutionSuffix}.${i}', 64) + name: take('module.private-dns-zone.${solutionSuffix}.${i}', 64) params: { name: zone tags: tags @@ -600,8 +599,8 @@ module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.1' = [ } ] -module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking && empty(existingProjectResourceId)) { - name: take('avm.res.network.private-endpoint.${solutionSuffix}', 64) +module cognitiveServicePrivateEndpoint './modules/networking/private-endpoint.bicep' = if (enablePrivateNetworking && empty(existingProjectResourceId)) { + name: take('module.private-endpoint.${solutionSuffix}', 64) params: { name: 'pep-aiservices-${solutionSuffix}' location: location @@ -655,10 +654,11 @@ module avmManagedIdentity './modules/identity/managed-identity.bicep' = { } } -module avmContainerRegistryReader 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { - name: take('avm.res.managed-identity.user-assigned-identity.${solutionSuffix}', 64) +module avmContainerRegistryReader './modules/identity/managed-identity.bicep' = { + name: take('module.managed-identity-acr.${solutionSuffix}', 64) params: { - name: 'id-acr-${solutionSuffix}' + solutionName: solutionSuffix + identityName: 'id-acr-${solutionSuffix}' location: location tags: tags enableTelemetry: enableTelemetry @@ -690,8 +690,8 @@ module avmContainerRegistry './modules/compute/container-registry.bicep' = { } } -module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { - name: take('avm.res.app.managed-environment.${solutionSuffix}', 64) +module avmContainerAppEnv './modules/compute/container-app-environment.bicep' = { + name: take('module.container-app-environment.${solutionSuffix}', 64) params: { name: 'cae-${solutionSuffix}' location: location @@ -713,646 +713,148 @@ module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = { } ] enableTelemetry: enableTelemetry - publicNetworkAccess: 'Enabled' // Always enabled for Container Apps Environment - - // <========== WAF related parameters - + publicNetworkAccess: 'Enabled' platformReservedCidr: '172.17.17.0/24' platformReservedDnsIP: '172.17.17.17' - zoneRedundant: (enablePrivateNetworking) ? true : false // Enable zone redundancy if private networking is enabled + zoneRedundant: (enablePrivateNetworking) ? true : false infrastructureSubnetResourceId: (enablePrivateNetworking) - ? virtualNetwork!.outputs.webserverfarmSubnetResourceId // Use the container app subnet - : null // Use the container app subnet + ? virtualNetwork!.outputs.webserverfarmSubnetResourceId + : null } } -module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app.${solutionSuffix}', 64) +module avmContainerApp './modules/compute/container-app-processor.bicep' = { + name: take('module.container-app-processor.${solutionSuffix}', 64) params: { - name: 'ca-${solutionSuffix}-app' + solutionSuffix: solutionSuffix location: location environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enableScalability: enableScalability + enableMonitoring: enableMonitoring + appInsightsConnectionString: enableMonitoring ? applicationInsights.outputs.connectionString : '' + tags: tags enableTelemetry: enableTelemetry - registries: null - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - - containers: [ - { - name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessor' - } - ] - } + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } - tags: tags } } -module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-api.${solutionSuffix}', 64) +module avmContainerApp_API './modules/compute/container-app-api.bicep' = { + name: take('module.container-app-api.${solutionSuffix}', 64) params: { - name: 'ca-${solutionSuffix}-api' + solutionSuffix: solutionSuffix location: location environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enableScalability: enableScalability + enableMonitoring: enableMonitoring + appInsightsConnectionString: enableMonitoring ? applicationInsights.outputs.connectionString : '' tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorAPI' - } - ] - probes: [ - // Liveness Probe - Checks if the app is still running - { - type: 'Liveness' - httpGet: { - path: '/startup' // Your app must expose this endpoint - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - // Readiness Probe - Checks if the app is ready to receive traffic - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 // Wait 10s before checking - periodSeconds: 5 // Check every 15s - failureThreshold: 10 // Restart if it fails 5 times - } - ] - } + enableTelemetry: enableTelemetry + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId ] - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - ingressExternal: true - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - corsPolicy: { - allowedOrigins: [ - '*' - ] - allowedMethods: [ - 'GET' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - ] - allowedHeaders: [ - 'Authorization' - 'Content-Type' - '*' - ] - } } } -module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-web.${solutionSuffix}', 64) +module avmContainerApp_Web './modules/compute/container-app-web.bicep' = { + name: take('module.container-app-web.${solutionSuffix}', 64) params: { - name: 'ca-${solutionSuffix}-web' + solutionSuffix: solutionSuffix location: location environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enableScalability: enableScalability tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - ingressExternal: true - ingressTargetPort: 3000 - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-web' - image: '${containerRegistryEndpoint}/contentprocessorweb:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_API_BASE_URL' - value: 'https://${avmContainerApp_API.outputs.fqdn}' - } - { - name: 'APP_WEB_CLIENT_ID' - value: '' - } - { - name: 'APP_WEB_AUTHORITY' - value: '${environment().authentication.loginEndpoint}/${tenant().tenantId}' - } - { - name: 'APP_WEB_SCOPE' - value: '' - } - { - name: 'APP_API_SCOPE' - value: '' - } - { - name: 'APP_REDIRECT_URL' - value: '/' - } - { - name: 'APP_POST_REDIRECT_URL' - value: '/' - } - { - name: 'APP_CONSOLE_LOG_ENABLED' - value: 'false' - } - ] - } + enableTelemetry: enableTelemetry + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId ] + apiAppFqdn: avmContainerApp_API.outputs.fqdn } } -module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-wkfl.${solutionSuffix}', 64) +module avmContainerApp_Workflow './modules/compute/container-app-workflow.bicep' = { + name: take('module.container-app-workflow.${solutionSuffix}', 64) params: { - name: 'ca-${solutionSuffix}-wkfl' + solutionSuffix: solutionSuffix location: location environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - enableTelemetry: enableTelemetry - registries: null + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enableScalability: enableScalability + enableMonitoring: enableMonitoring + appInsightsConnectionString: enableMonitoring ? applicationInsights.outputs.connectionString : '' tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: '' - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorWorkflow' - } - ] - } + enableTelemetry: enableTelemetry + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } } } -module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-update.${solutionSuffix}', 64) +module avmContainerApp_update './modules/compute/container-app-processor.bicep' = { + name: take('module.container-app-processor.update.${solutionSuffix}', 64) params: { - name: 'ca-${solutionSuffix}-app' + solutionSuffix: solutionSuffix location: location - enableTelemetry: enableTelemetry environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enableScalability: enableScalability + enableMonitoring: enableMonitoring + appInsightsConnectionString: enableMonitoring ? applicationInsights.outputs.connectionString : '' tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessor' - } - ] - } + enableTelemetry: enableTelemetry + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: enableScalability - ? [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: 100 - } - } - } - ] - : [] - } + appConfigEndpoint: avmAppConfig.outputs.endpoint } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] } -module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) +module avmContainerApp_API_update './modules/compute/container-app-api.bicep' = { + name: take('module.container-app-api.update.${solutionSuffix}', 64) params: { - name: 'ca-${solutionSuffix}-api' + solutionSuffix: solutionSuffix location: location - enableTelemetry: enableTelemetry environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enableScalability: enableScalability + enableMonitoring: enableMonitoring + appInsightsConnectionString: enableMonitoring ? applicationInsights.outputs.connectionString : '' tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - - containers: [ - { - name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorAPI' - } - ] - probes: [ - // Liveness Probe - Checks if the app is still running - { - type: 'Liveness' - httpGet: { - path: '/startup' // Your app must expose this endpoint - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - // Readiness Probe - Checks if the app is ready to receive traffic - { - type: 'Readiness' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - } - { - type: 'Startup' - httpGet: { - path: '/startup' - port: 80 - scheme: 'HTTP' - } - initialDelaySeconds: 20 // Wait 10s before checking - periodSeconds: 5 // Check every 15s - failureThreshold: 10 // Restart if it fails 5 times - } - ] - } + enableTelemetry: enableTelemetry + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId ] - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - rules: [ - { - name: 'http-scaler' - http: { - metadata: { - concurrentRequests: '100' - } - } - } - ] - } - ingressExternal: true - activeRevisionsMode: 'Single' - ingressTransport: 'auto' - ingressAllowInsecure: false - corsPolicy: { - allowedOrigins: [ - '*' - ] - allowedMethods: [ - 'GET' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - ] - allowedHeaders: [ - 'Authorization' - 'Content-Type' - '*' - ] - } + appConfigEndpoint: avmAppConfig.outputs.endpoint } - dependsOn: [ - cognitiveServicePrivateEndpoint - ] } -module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) +module avmContainerApp_Workflow_update './modules/compute/container-app-workflow.bicep' = { + name: take('module.container-app-workflow.update.${solutionSuffix}', 64) params: { - name: 'ca-${solutionSuffix}-wkfl' + solutionSuffix: solutionSuffix location: location - enableTelemetry: enableTelemetry environmentResourceId: avmContainerAppEnv.outputs.resourceId - workloadProfileName: 'Consumption' - registries: null + containerRegistryEndpoint: containerRegistryEndpoint + imageTag: imageTag + enableScalability: enableScalability + enableMonitoring: enableMonitoring + appInsightsConnectionString: enableMonitoring ? applicationInsights.outputs.connectionString : '' tags: tags - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [ - avmContainerRegistryReader.outputs.resourceId - ] - } - containers: [ - { - name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' - resources: { - cpu: 4 - memory: '8.0Gi' - } - env: [ - { - name: 'APP_CONFIG_ENDPOINT' - value: avmAppConfig.outputs.endpoint - } - { - name: 'APP_ENV' - value: 'prod' - } - { - name: 'APP_LOGGING_LEVEL' - value: 'INFO' - } - { - name: 'AZURE_PACKAGE_LOGGING_LEVEL' - value: 'WARNING' - } - { - name: 'AZURE_LOGGING_PACKAGES' - value: '' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? applicationInsights.outputs.connectionString : '' - } - { - name: 'OTEL_SERVICE_NAME' - value: 'ContentProcessorWorkflow' - } - ] - } + enableTelemetry: enableTelemetry + userAssignedResourceIds: [ + avmContainerRegistryReader.outputs.resourceId ] - activeRevisionsMode: 'Single' - ingressExternal: false - disableIngress: true - scaleSettings: { - maxReplicas: enableScalability ? 3 : 2 - minReplicas: enableScalability ? 2 : 1 - } + appConfigEndpoint: avmAppConfig.outputs.endpoint } } @@ -1461,8 +963,8 @@ module avmAiSearch './modules/ai/ai-search.bicep' = { // Module: Data (Storage, Cosmos DB, App Configuration) // ============================================================================ -module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { - name: take('avm.res.storage.storage-account.${solutionSuffix}', 64) +module avmStorageAccount './modules/data/storage-account.bicep' = { + name: take('module.storage-account.${solutionSuffix}', 64) params: { name: 'st${replace(solutionSuffix, '-', '')}' location: location @@ -1515,8 +1017,6 @@ module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { supportsHttpsTrafficOnly: true accessTier: 'Hot' tags: tags - - //<======================= WAF related parameters allowBlobPublicAccess: false publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled' privateEndpoints: (enablePrivateNetworking) @@ -1532,7 +1032,7 @@ module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { } ] } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId service: 'blob' } { @@ -1546,7 +1046,7 @@ module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { } ] } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId service: 'queue' } ] @@ -1577,8 +1077,8 @@ module avmCosmosDB './modules/data/cosmos-db-mongo.bicep' = { } } -module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { - name: take('avm.res.app-configuration.configuration-store.${solutionSuffix}', 64) +module avmAppConfig './modules/data/app-configuration.bicep' = { + name: take('module.app-configuration.${solutionSuffix}', 64) params: { name: 'appcs-${solutionSuffix}' location: location @@ -1604,7 +1104,7 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 ] : null disableLocalAuth: false - replicaLocations: enableRedundancy? [{ replicaLocation: replicaLocation }] : [] + replicaLocations: enableRedundancy ? [{ replicaLocation: replicaLocation }] : [] roleAssignments: [ { principalId: avmContainerApp.outputs.?systemAssignedMIPrincipalId! @@ -1630,7 +1130,7 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 keyValues: [ { name: 'APP_AZURE_OPENAI_ENDPOINT' - value: avmAiServices.outputs.endpoint //TODO: replace with actual endpoint + value: avmAiServices.outputs.endpoint } { name: 'APP_AZURE_OPENAI_MODEL' @@ -1700,7 +1200,6 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 name: 'APP_COSMOS_CONNSTR' value: avmCosmosDB.outputs.primaryReadWriteConnectionString } - // ===== v2 Workflow Keys ===== // { name: 'APP_COSMOS_CONTAINER_BATCH_PROCESS' value: 'claimprocesses' @@ -1753,7 +1252,6 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 name: 'AZURE_OPENAI_ENDPOINT_BASE' value: avmAiServices.outputs.endpoint } - // ===== Agent Framework Keys ===== // { name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' value: '' @@ -1770,7 +1268,6 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 name: 'GLOBAL_LLM_SERVICE' value: 'AzureOpenAI' } - // ===== GPT-5 Service Prefix Keys ===== // { name: 'GPT5_API_VERSION' value: '2025-03-01-preview' @@ -1783,7 +1280,6 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 name: 'GPT5_ENDPOINT' value: avmAiServices.outputs.endpoint } - // ===== PHI-4 Service Prefix Keys ===== // { name: 'PHI4_API_VERSION' value: '2024-05-01-preview' @@ -1797,13 +1293,12 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9 value: avmAiServices.outputs.endpoint } ] - publicNetworkAccess: 'Enabled' } } -module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = if (enablePrivateNetworking) { - name: take('avm.res.app-configuration.configuration-store.update.${solutionSuffix}', 64) +module avmAppConfig_update './modules/data/app-configuration.bicep' = if (enablePrivateNetworking) { + name: take('module.app-configuration.update.${solutionSuffix}', 64) params: { name: 'appcs-${solutionSuffix}' location: location @@ -1823,7 +1318,7 @@ module avmAppConfig_update 'br/public:avm/res/app-configuration/configuration-st } ] } - subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet + subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId } ] } diff --git a/infra/avm/main.json b/infra/avm/main.json index eabf3776..ca69c6d6 100644 --- a/infra/avm/main.json +++ b/infra/avm/main.json @@ -1,15 +1,12 @@ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "17324347463484125167" - }, - "name": "Content Processing Solution Accelerator", - "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." + "templateHash": "4609875019148099503" + } }, "parameters": { "solutionName": { @@ -40,6 +37,97 @@ "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" + }, + "description": "Optional. Tags to be applied to the resources." + }, + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + } + }, + "createdBy": { + "type": "string", + "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", + "metadata": { + "description": "Optional. Tag, Created by user name." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable WAF for the deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + } + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enableScalability": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable purge protection. Defaults to false." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminUsername": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, "azureAiServiceLocation": { "type": "string", "allowedValues": [ @@ -118,61 +206,6 @@ "description": "Optional. The image tag for the container images." } }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable WAF for the deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableMonitoring": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." - } - }, - "enableRedundancy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." - } - }, - "enableScalability": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable purge protection. Defaults to false." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" - }, - "description": "Optional. Tags to be applied to the resources." - }, - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - } - }, "existingLogAnalyticsWorkspaceId": { "type": "string", "defaultValue": "", @@ -186,42 +219,6 @@ "metadata": { "description": "Use this parameter to use an existing AI project resource ID" } - }, - "vmSize": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." - } - }, - "vmAdminUsername": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." - } - }, - "vmAdminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." - } - }, - "solutionUniqueText": { - "type": "string", - "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", - "maxLength": 5, - "metadata": { - "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." - } - }, - "createdBy": { - "type": "string", - "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", - "metadata": { - "description": "Optional. Tag, Created by user name." - } } }, "variables": { @@ -268,8 +265,16 @@ "containerRegistry": 8 } }, - "resources": { - "avmTelemetry": { + "resources": [ + { + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", + "properties": { + "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" + } + }, + { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", @@ -289,19 +294,11 @@ } } }, - "resourceGroupTags": { - "type": "Microsoft.Resources/tags", - "apiVersion": "2025-04-01", - "name": "default", - "properties": { - "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" - } - }, - "virtualNetwork": { - "condition": "[parameters('enablePrivateNetworking')]", + { + "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -311,10 +308,8 @@ "solutionName": { "value": "[variables('solutionSuffix')]" }, - "addressPrefixes": { - "value": [ - "10.0.0.0/8" - ] + "name": { + "value": "[variables('logAnalyticsWorkspaceResourceName')]" }, "location": { "value": "[parameters('location')]" @@ -322,12 +317,14 @@ "tags": { "value": "[parameters('tags')]" }, - "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "resourceSuffix": { - "value": "[variables('solutionSuffix')]" - }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" + }, + "enableReplication": { + "value": "[parameters('enableRedundancy')]" + }, + "replicationLocation": { + "value": "[variables('replicaLocation')]" } }, "template": { @@ -338,410 +335,150 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "10323079586505814920" + "templateHash": "9919485194443011422" } }, - "definitions": { - "subnetOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the subnet." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the subnet." - } - }, - "nsgName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The name of the associated NSG, if any." - } - }, - "nsgResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The resource ID of the associated NSG, if any." - } - } - }, + "parameters": { + "solutionName": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "Subnet output type" + "description": "Solution name suffix used to derive the resource name." } }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the subnet." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. Address prefixes for the subnet." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Delegation for the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Private endpoint network policies." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Private link service network policies." - } - }, - "networkSecurityGroup": { - "$ref": "#/definitions/networkSecurityGroupType", - "nullable": true, - "metadata": { - "description": "Optional. NSG configuration for the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Route table resource ID." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. Service endpoint policies." - } - }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Service endpoints to enable." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Disable default outbound connectivity." - } - } - }, + "name": { + "type": "string", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", "metadata": { - "__bicep_export!": true, - "description": "Subnet configuration type" + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." } }, - "networkSecurityGroupType": { + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NSG." - } - }, - "securityRules": { - "type": "array", - "items": { - "type": "object" - }, - "metadata": { - "description": "Required. Security rules for the NSG." - } - } - }, + "defaultValue": {}, "metadata": { - "__bicep_export!": true, - "description": "NSG configuration type" + "description": "Tags to apply to the resource." } - } - }, - "parameters": { - "solutionName": { + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days. WAF recommends 365." + } + }, + "skuName": { "type": "string", + "defaultValue": "PerGB2018", "metadata": { - "description": "Solution name suffix used to derive the resource name." + "description": "SKU name for the workspace." } }, - "location": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "publicNetworkAccessForIngestion": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "Enabled", "metadata": { - "description": "Azure region for the resource." + "description": "Public network access for ingestion." } }, - "addressPrefixes": { - "type": "array", + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Address prefixes for the virtual network." + "description": "Public network access for query." } }, - "subnets": { + "enableReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable workspace replication for redundancy." + } + }, + "replicationLocation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Replication location (paired region)." + } + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." + } + }, + "dataSources": { "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "defaultValue": [ - { - "name": "backend", - "addressPrefixes": [ - "10.0.0.0/27" - ], - "networkSecurityGroup": { - "name": "nsg-backend", - "securityRules": [ + "defaultValue": [], + "metadata": { + "description": "Data sources for VM monitoring (Windows events, perf counters)." + } + } + }, + "resources": { + "workspace": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": "[parameters('retentionInDays')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "diagnosticSettings": { + "value": [ { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "destinationAddressPrefix": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "direction": "Outbound", - "priority": 200, - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*" - } + "useThisWorkspace": true } ] - } - }, - { - "name": "webserverfarm", - "addressPrefixes": [ - "10.0.4.0/27" - ], - "delegation": "Microsoft.Web/serverfarms", - "privateEndpointNetworkPolicies": "Enabled", - "privateLinkServiceNetworkPolicies": "Enabled", - "networkSecurityGroup": { - "name": "nsg-webserverfarm", - "securityRules": [ - { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "destinationAddressPrefix": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "direction": "Outbound", - "priority": 200, - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*" - } - } - ] - } - }, - { - "name": "administration", - "addressPrefixes": [ - "10.0.0.32/27" - ], - "networkSecurityGroup": { - "name": "nsg-administration", - "securityRules": [ - { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "destinationAddressPrefix": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "direction": "Outbound", - "priority": 200, - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*" - } - } - ] - } - }, - { - "name": "AzureBastionSubnet", - "addressPrefixes": [ - "10.0.0.64/26" - ], - "networkSecurityGroup": { - "name": "nsg-bastion", - "securityRules": [ - { - "name": "AllowGatewayManager", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2702, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "GatewayManager", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowHttpsInBound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2703, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "Internet", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowSshRdpOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 100, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AllowAzureCloudOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 110, - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "AzureCloud" - } - } - ] - } - } - ], - "metadata": { - "description": "Subnet configurations." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resources." - } - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the Log Analytics Workspace for diagnostics." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "resourceSuffix": { - "type": "string", - "metadata": { - "description": "Suffix for resource naming." - } - } - }, - "variables": { - "name": "[format('vnet-{0}', parameters('solutionName'))]" - }, - "resources": { - "nsgs": { - "copy": { - "name": "nsgs", - "count": "[length(parameters('subnets'))]", - "mode": "serial", - "batchSize": 1 - }, - "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" }, - "securityRules": { - "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" + "publicNetworkAccessForIngestion": { + "value": "[parameters('publicNetworkAccessForIngestion')]" }, - "tags": { - "value": "[parameters('tags')]" + "publicNetworkAccessForQuery": { + "value": "[parameters('publicNetworkAccessForQuery')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } + "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", + "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", + "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -750,174 +487,14 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7311263652424030280" + "version": "0.39.26.7824", + "templateHash": "14099489006827800075" }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace." }, "definitions": { - "securityRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "metadata": { - "description": "Required. The properties of the security rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a security rule." - } - }, - "diagnosticSettingLogsOnlyType": { + "diagnosticSettingType": { "type": "object", "properties": { "name": { @@ -960,6 +537,31 @@ "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ @@ -971,6 +573,13 @@ "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, "workspaceResourceId": { "type": "string", "nullable": true, @@ -1006,848 +615,553 @@ "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } }, - "lockType": { + "gallerySolutionType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." } }, - "notes": { - "type": "string", - "nullable": true, + "plan": { + "$ref": "#/definitions/solutionPlanType", "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "Properties of the gallery solutions to be created in the log analytics workspace." } }, - "roleAssignmentType": { + "storageInsightsConfigType": { "type": "object", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { + "storageAccountResourceId": { "type": "string", "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Required. Resource ID of the storage account to be linked." } }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], + "containers": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The names of the blob containers that the workspace should read." } }, - "description": { - "type": "string", + "tables": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. List of tables to be read by the workspace." } - }, - "condition": { + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the storage insights configuration." + } + }, + "linkedServiceType": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." } }, - "conditionVersion": { + "resourceId": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." } }, - "delegatedManagedIdentityResourceId": { + "writeAccessResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "__bicep_export!": true, + "description": "Properties of the linked service." } }, - "tags": { + "linkedStorageAccountType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" - }, - "description": "Optional. Tags of the NSG resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", - "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" - } - } + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." + } }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "addressPrefixes": { - "value": "[parameters('addressPrefixes')]" - }, - "subnets": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('subnets'))]", - "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" - } - ] - }, - "diagnosticSettings": { - "value": [ - { - "name": "vnetDiagnostics", - "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", - "logCategoriesAndGroups": [ - { - "categoryGroup": "allLogs", - "enabled": true - } - ], - "metricCategories": [ - { - "category": "AllMetrics", - "enabled": true - } - ] + "__bicep_export!": true, + "description": "Properties of the linked storage account." } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "11272001757446231867" }, - "name": "Virtual Networks", - "description": "This module deploys a Virtual Network (vNet)." - }, - "definitions": { - "peeringType": { + "savedSearchType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + "description": "Required. Name of the saved search." } }, - "remoteVirtualNetworkResourceId": { + "etag": { "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." } }, - "allowGatewayTransit": { - "type": "bool", - "nullable": true, + "category": { + "type": "string", "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + "description": "Required. The category of the saved search. This helps the user to find a saved search faster." } }, - "allowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, + "displayName": { + "type": "string", "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + "description": "Required. Display name for the search." } }, - "doNotVerifyRemoteGateways": { - "type": "bool", + "functionAlias": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + "description": "Optional. The function alias if query serves as a function." } }, - "useRemoteGateways": { - "type": "bool", + "functionParameters": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." } }, - "remotePeeringEnabled": { - "type": "bool", - "nullable": true, + "query": { + "type": "string", "metadata": { - "description": "Optional. Deploy the outbound and the inbound peering." + "description": "Required. The query expression for the saved search." } }, - "remotePeeringName": { - "type": "string", + "tags": { + "type": "array", "nullable": true, "metadata": { - "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + "description": "Optional. The tags attached to the saved search." } }, - "remotePeeringAllowForwardedTraffic": { - "type": "bool", + "version": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + "description": "Optional. The version number of the query language. The current version is 2 and is the default." } - }, - "remotePeeringAllowGatewayTransit": { - "type": "bool", - "nullable": true, + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the saved search." + } + }, + "dataExportType": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + "description": "Required. Name of the data export." } }, - "remotePeeringAllowVirtualNetworkAccess": { - "type": "bool", + "destination": { + "$ref": "#/definitions/destinationType", "nullable": true, "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + "description": "Optional. The destination of the data export." } }, - "remotePeeringDoNotVerifyRemoteGateways": { + "enable": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + "description": "Optional. Enable or disable the data export." } }, - "remotePeeringUseRemoteGateways": { - "type": "bool", - "nullable": true, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + "description": "Required. The list of table names to export." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "Properties of the data export." } }, - "subnetType": { + "dataSourceType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The Name of the subnet resource." + "description": "Required. Name of the data source." } }, - "addressPrefix": { + "kind": { "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + "description": "Required. The kind of data source." } }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, + "linkedResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + "description": "Optional. The resource id of the resource that will be linked to the workspace." } }, - "ipamPoolPrefixAllocations": { - "type": "array", - "prefixItems": [ - { - "type": "object", - "properties": { - "pool": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the IPAM pool." - } - } - }, - "metadata": { - "description": "Required. The Resource ID of the IPAM pool." - } - }, - "numberOfIpAddresses": { - "type": "string", - "metadata": { - "description": "Required. Number of IP addresses allocated from the pool." - } - } - } - } - ], - "items": false, + "eventLogName": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." + "description": "Optional. The name of the event log to configure when kind is WindowsEvent." } }, - "applicationGatewayIPConfigurations": { + "eventTypes": { "type": "array", - "items": { - "type": "object" - }, "nullable": true, "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "description": "Optional. The event types to configure when kind is WindowsEvent." } }, - "delegation": { + "objectName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The delegation to enable on the subnet." + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." } }, - "natGatewayResourceId": { + "instanceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." } }, - "networkSecurityGroupResourceId": { - "type": "string", + "intervalSeconds": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." } }, - "privateEndpointNetworkPolicies": { + "performanceCounters": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], "nullable": true, "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." } }, - "privateLinkServiceNetworkPolicies": { + "state": { "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], "nullable": true, "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." } }, - "roleAssignments": { + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Severities to configure when kind is LinuxSyslog." } }, - "routeTableResourceId": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data source." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "plan": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." + "description": "Optional. The plan for the table." } }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", "nullable": true, "metadata": { - "description": "Optional. An array of service endpoint policies." + "description": "Optional. The restored logs for the table." } }, - "serviceEndpoints": { + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. The schema for the table." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. The search results for the table." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + } + }, + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." + "description": "Optional. The role assignments for the table." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the custom table." + } + }, + "workspaceFeaturesType": { + "type": "object", + "properties": { + "disableLocalAuth": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable Non-EntraID based Auth. Default is true." } }, - "defaultOutboundAccess": { + "enableDataExport": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + "description": "Optional. Flag that indicate if data should be exported." } }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], + "enableLogAccessUsingOnlyResourcePermissions": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + "description": "Optional. Enable log access using only resource permissions. Default is false." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that describes if we want to remove the data after 30 days." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "Features of the workspace." } }, - "diagnosticSettingFullType": { + "workspaceReplicationType": { "type": "object", "properties": { - "name": { - "type": "string", + "enabled": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." } }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, + "location": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Replication properties of the workspace." + } + }, + "_1.columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Required. The column name." } }, - "logAnalyticsDestinationType": { + "type": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" ], - "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Required. The column type." } }, - "workspaceResourceId": { + "dataTypeHint": { "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The column data type logical hint." } }, - "storageAccountResourceId": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The column description." } }, - "eventHubAuthorizationRuleResourceId": { + "displayName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. Column display name." } - }, - "eventHubName": { + } + }, + "metadata": { + "description": "The parameters of the table column.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "destinationType": { + "type": "object", + "properties": { + "resourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Required. The destination resource ID." } }, - "marketplacePartnerResourceId": { - "type": "string", + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. The destination metadata." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "The data export destination properties.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + "sourceTemplate": "data-export/main.bicep" } } }, @@ -1884,7 +1198,67 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the restore operation that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" } } }, @@ -1959,7 +1333,122 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "description": "The table schema.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the search job that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" } } } @@ -1968,7 +1457,7 @@ "name": { "type": "string", "metadata": { - "description": "Required. The name of the Virtual Network (vNet)." + "description": "Required. Name of the Log Analytics workspace." } }, "location": { @@ -1978,99 +1467,204 @@ "description": "Optional. Location for all resources." } }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." - } - }, - "ipamPoolNumberOfIpAddresses": { + "skuName": { "type": "string", - "nullable": true, + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], "metadata": { - "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." + "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." } }, - "virtualNetworkBgpCommunity": { - "type": "string", - "nullable": true, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, "metadata": { - "description": "Optional. The BGP community associated with the virtual network." + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." } }, - "subnets": { + "storageInsightsConfigs": { "type": "array", "items": { - "$ref": "#/definitions/subnetType" + "$ref": "#/definitions/storageInsightsConfigType" }, "nullable": true, "metadata": { - "description": "Optional. An Array of subnets to deploy to the Virtual Network." + "description": "Optional. List of storage accounts to be read by the workspace." } }, - "dnsServers": { + "linkedServices": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/linkedServiceType" }, "nullable": true, "metadata": { - "description": "Optional. DNS Servers associated to the Virtual Network." + "description": "Optional. List of services to be linked." } }, - "ddosProtectionPlanResourceId": { - "type": "string", + "linkedStorageAccounts": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedStorageAccountType" + }, "nullable": true, "metadata": { - "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." } }, - "peerings": { + "savedSearches": { "type": "array", "items": { - "$ref": "#/definitions/peeringType" + "$ref": "#/definitions/savedSearchType" }, "nullable": true, "metadata": { - "description": "Optional. Virtual Network Peering configurations." + "description": "Optional. Kusto Query Language searches to save." } }, - "vnetEncryption": { + "dataExports": { + "type": "array", + "items": { + "$ref": "#/definitions/dataExportType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "items": { + "$ref": "#/definitions/dataSourceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." + } + }, + "onboardWorkspaceToSentinel": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." } }, - "vnetEncryptionEnforcement": { + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { "type": "string", - "defaultValue": "AllowUnencrypted", + "defaultValue": "-1", + "metadata": { + "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." + } + }, + "defaultDataCollectionRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", "allowedValues": [ - "AllowUnencrypted", - "DropUnencrypted" + "Enabled", + "Disabled", + "SecuredByPerimeter" ], "metadata": { - "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + "description": "Optional. The network access type for accessing Log Analytics ingestion." } }, - "flowTimeoutInMinutes": { - "type": "int", - "defaultValue": 0, - "maxValue": 30, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], "metadata": { - "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "features": { + "$ref": "#/definitions/workspaceFeaturesType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace features." + } + }, + "replication": { + "$ref": "#/definitions/workspaceReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace replication properties." } }, "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/diagnosticSettingType" }, "nullable": true, "metadata": { "description": "Optional. The diagnostic settings of the service." } }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, "lock": { "$ref": "#/definitions/lockType", "nullable": true, @@ -2090,10 +1684,13 @@ }, "tags": { "type": "object", - "nullable": true, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" + }, "description": "Optional. Tags of the resource." - } + }, + "nullable": true }, "enableTelemetry": { "type": "bool", @@ -2101,24 +1698,6 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "enableVmProtection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." - } - }, - "enablePrivateEndpointVNetPolicies": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Basic", - "Disabled" - ], - "metadata": { - "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." - } } }, "variables": { @@ -2130,12 +1709,19 @@ } ], "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -2144,7 +1730,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2160,46 +1746,44 @@ } } }, - "virtualNetwork": { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-05-01", + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", - "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", - "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", - "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", - "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", - "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", - "enableVmProtection": "[parameters('enableVmProtection')]", - "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" - } - }, - "virtualNetwork_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", + "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", + "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", + "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]", + "replication": "[parameters('replication')]", + "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" }, - "dependsOn": [ - "virtualNetwork" - ] + "identity": "[variables('identity')]" }, - "virtualNetwork_diagnosticSettings": { + "logAnalyticsWorkspace_diagnosticSettings": { "copy": { - "name": "virtualNetwork_diagnosticSettings", + "name": "logAnalyticsWorkspace_diagnosticSettings", "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -2223,25 +1807,50 @@ } ], "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "virtualNetwork" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_roleAssignments": { + "logAnalyticsWorkspace_sentinelOnboarding": { + "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", + "type": "Microsoft.SecurityInsights/onboardingStates", + "apiVersion": "2025-09-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "default", + "properties": {}, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { "copy": { - "name": "virtualNetwork_roleAssignments", + "name": "logAnalyticsWorkspace_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -2252,78 +1861,34 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "virtualNetwork" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_subnets": { + "logAnalyticsWorkspace_storageInsightConfigs": { "copy": { - "name": "virtualNetwork_subnets", - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "mode": "serial", - "batchSize": 1 + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "virtualNetworkName": { + "logAnalyticsWorkspaceName": { "value": "[parameters('name')]" }, - "name": { - "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" - }, - "addressPrefix": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" - }, - "addressPrefixes": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" - }, - "ipamPoolPrefixAllocations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" - }, - "applicationGatewayIPConfigurations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" - }, - "delegation": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" - }, - "natGatewayResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" - }, - "networkSecurityGroupResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" - }, - "privateEndpointNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" - }, - "privateLinkServiceNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "routeTableResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" - }, - "serviceEndpointPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" - }, - "serviceEndpoints": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" - }, - "defaultOutboundAccess": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + "containers": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" }, - "sharingScope": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + "tables": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "storageAccountResourceId": { + "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" } }, "template": { @@ -2333,2127 +1898,2105 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13992200806189615656" + "version": "0.39.26.7824", + "templateHash": "140290971998938797" }, - "name": "Virtual Network Subnets", - "description": "This module deploys a Virtual Network Subnet." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - } + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." }, "parameters": { - "name": { + "logAnalyticsWorkspaceName": { "type": "string", "metadata": { - "description": "Required. The Name of the subnet resource." + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "virtualNetworkName": { + "name": { "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", "metadata": { - "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + "description": "Optional. The name of the storage insights config." } }, - "addressPrefix": { + "storageAccountResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + "description": "Required. The Azure Resource Manager ID of the storage account resource." } }, - "ipamPoolPrefixAllocations": { + "containers": { "type": "array", "items": { - "type": "object" + "type": "string" }, "nullable": true, "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." + "description": "Optional. The names of the blob containers that the workspace should read." } }, - "serviceEndpoints": { + "tables": { "type": "array", "items": { "type": "string" }, - "defaultValue": [], - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "delegation": { - "type": "string", "nullable": true, "metadata": { - "description": "Optional. The delegation to enable on the subnet." + "description": "Optional. The names of the Azure tables that the workspace should read." } }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, + "tags": { + "type": "object", "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" }, - "privateEndpointNetworkPolicies": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "metadata": { - "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." - } + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + } } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." }, - "nullable": true, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." - } + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "14482465616812596213" }, - "sharingScope": { + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], + "name": { + "type": "string", "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "description": "Required. Name of the link." } }, - "serviceEndpointPolicies": { - "type": "array", - "defaultValue": [], + "resourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. An array of service endpoint policies." + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, + "writeAccessResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "tags": { + "type": "object", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "virtualNetwork": { + "workspace": { "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[parameters('virtualNetworkName')]" + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" }, - "subnet": { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "serviceEndpoints", - "count": "[length(parameters('serviceEndpoints'))]", - "input": { - "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" - } - } - ], - "addressPrefix": "[parameters('addressPrefix')]", - "addressPrefixes": "[parameters('addressPrefixes')]", - "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", - "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", - "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", - "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", - "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", - "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", - "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", - "sharingScope": "[parameters('sharingScope')]" + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" } - }, - "subnet_roleAssignments": { - "copy": { - "name": "subnet_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "subnet" - ] } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, "name": { "type": "string", "metadata": { - "description": "The name of the virtual network peering." + "description": "The name of the deployed linked service." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource ID of the deployed linked service." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" }, - "addressPrefix": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The address prefix for the subnet." - }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "List of address prefixes for the subnet." - }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" - }, - "ipamPoolPrefixAllocations": { - "type": "array", - "metadata": { - "description": "The IPAM pool prefix allocations for the subnet." + "description": "The resource group where the linked service is deployed." }, - "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "virtualNetwork" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_peering_local": { + "logAnalyticsWorkspace_linkedStorageAccounts": { "copy": { - "name": "virtualNetwork_peering_local", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "localVnetName": { + "logAnalyticsWorkspaceName": { "value": "[parameters('name')]" }, - "remoteVirtualNetworkResourceId": { - "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" - }, "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" - }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" - }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" - }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" - }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + "storageAccountIds": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "6939030350004475953" + "version": "0.39.26.7824", + "templateHash": "14864721709229272590" }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." }, "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { + "logAnalyticsWorkspaceName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "remoteVirtualNetworkResourceId": { + "name": { "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + "description": "Required. Name of the link." } }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + "description": "Required. Linked storage accounts resources Ids." } } }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } + "storageAccountIds": "[parameters('storageAccountIds')]" } } - ], + }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the virtual network peering was deployed into." + "description": "The name of the deployed linked storage account." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the virtual network peering." + "description": "The resource ID of the deployed linked storage account." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" }, - "resourceId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource group where the linked storage account is deployed." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_peering_remote": { + "logAnalyticsWorkspace_savedSearches": { "copy": { - "name": "virtualNetwork_peering_remote", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" }, - "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", - "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "localVnetName": { - "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" }, "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + "etag": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + "displayName": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + "category": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + "query": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + "functionAlias": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "6939030350004475953" + "version": "0.39.26.7824", + "templateHash": "17904092372918022238" }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." }, "parameters": { - "name": { + "logAnalyticsWorkspaceName": { "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "localVnetName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + "description": "Required. Name of the saved search." } }, - "remoteVirtualNetworkResourceId": { + "displayName": { "type": "string", "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + "description": "Required. Display name for the search." } }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, + "category": { + "type": "string", "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + "description": "Required. Query category." } }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, + "query": { + "type": "string", "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + "description": "Required. Kusto Query to be stored." } }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, + "tags": { + "type": "array", "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." } }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, + "functionParameters": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." } }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, + "version": { + "type": "int", + "nullable": true, "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." } } }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" } } - ], + }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the virtual network peering was deployed into." + "description": "The resource group where the saved search is deployed." }, "value": "[resourceGroup().name]" }, "name": { "type": "string", "metadata": { - "description": "The name of the virtual network peering." + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] + }, + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17943947755417749524" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource ID of the data export." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" + "logAnalyticsWorkspace" ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network." - }, - "value": "[parameters('name')]" - }, - "subnetNames": { - "type": "array", - "metadata": { - "description": "The names of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" - } }, - "subnetResourceIds": { - "type": "array", - "metadata": { - "description": "The resource IDs of the deployed subnets." - }, + "logAnalyticsWorkspace_dataSources": { "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(coalesce(parameters('dataSources'), createArray()))]" }, - "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "nsgs" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.name.value]" - }, - "resourceId": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetOutputType" - }, - "copy": { - "count": "[length(parameters('subnets'))]", - "input": { - "name": "[parameters('subnets')[copyIndex()].name]", - "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", - "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", - "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" - } - } - }, - "backendSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" - }, - "webserverfarmSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" - }, - "administrationSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" - }, - "bastionSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "bastionHost": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('bastionHostName')]" - }, - "skuName": { - "value": "Standard" - }, - "location": { - "value": "[parameters('location')]" - }, - "virtualNetworkResourceId": { - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "publicIPAddressObject": { - "value": { - "name": "[format('pip-{0}', variables('bastionHostName'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7741601918225805390" - }, - "name": "Bastion Hosts", - "description": "This module deploys a Bastion Host." - }, - "definitions": { - "publicIPAddressObjectType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for the Public IP resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create for the Public IP resource." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable usage telemetry for the Public IP module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Idle timeout in minutes for the Public IP resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to apply to the Public IP resource." - }, - "nullable": true - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the Public IP resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" + }, + "kind": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "15360290236166491819" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure Bastion resource." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Shared services Virtual Network resource Id." - } - }, - "bastionSubnetPublicIpResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "publicIPAddressObject": { - "$ref": "#/definitions/publicIPAddressObjectType", - "defaultValue": { - "name": "[format('{0}-pip', parameters('name'))]" - }, - "metadata": { - "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Basic", - "allowedValues": [ - "Basic", - "Developer", - "Premium", - "Standard" - ], - "metadata": { - "description": "Optional. The SKU of this Bastion Host." - } - }, - "disableCopyPaste": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." - } - }, - "enableFileCopy": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." - } - }, - "enableIpConnect": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." - } - }, - "enableKerberos": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." - } - }, - "enableShareableLink": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." - } - }, - "enableSessionRecording": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." - } - }, - "enablePrivateOnlyBastion": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." - } - }, - "scaleUnits": { - "type": "int", - "defaultValue": 2, - "metadata": { - "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. The list of Availability zones to use for the zone-redundant resources." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "azureBastion": { - "type": "Microsoft.Network/bastionHosts", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[coalesce(parameters('tags'), createObject())]", - "sku": { - "name": "[parameters('skuName')]" - }, - "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", - "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", - "dependsOn": [ - "publicIPAddress" - ] - }, - "azureBastion_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_diagnosticSettings": { - "copy": { - "name": "azureBastion_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_roleAssignments": { - "copy": { - "name": "azureBastion_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "publicIPAddress": { - "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('publicIPAddressObject').name]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" - }, - "ipTags": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" - }, - "publicIPAddressVersion": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" - }, - "publicIPAllocationMethod": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" - }, - "publicIpPrefixResourceId": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" - }, - "skuName": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" - }, - "skuTier": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" - }, - "availabilityZones": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "16564959277054027786" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." - }, - "definitions": { - "dnsSettingsType": { - "type": "object", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" } }, - "reverseFqdn": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "18383178824663161801" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "lockType": { - "type": "object", + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Specify the notes of the lock." + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10255889523646649592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } } } }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" }, - "roleAssignmentType": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" + }, + "primarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The primary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" + }, + "secondarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The secondary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.name.value]" + }, + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." + }, + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + } + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appi-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "retentionInDays": { + "value": 365 + }, + "kind": { + "value": "web" + }, + "disableIpMasking": { + "value": false + }, + "flowType": { + "value": "Bluefield" + }, + "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7675188203537278510" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the Application Insights component." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days." + } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Application type for the component." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to disable IP masking." + } + }, + "flowType": { + "type": "string", + "defaultValue": "Bluefield", + "metadata": { + "description": "Flow type for the component." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Resource ID of the Log Analytics workspace connected to the component." + } + }, + "diagnosticSettings": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings to apply to the component." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + } + }, + "resources": { + "appInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.component.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "retentionInDays": { + "value": "[parameters('retentionInDays')]" + }, + "kind": { + "value": "[parameters('kind')]" + }, + "disableIpMasking": { + "value": "[parameters('disableIpMasking')]" + }, + "flowType": { + "value": "[parameters('flowType')]" + }, + "workspaceResourceId": { + "value": "[parameters('workspaceResourceId')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17358780145253914698" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance." + }, + "definitions": { + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Optional. The name of the diagnostic setting." } }, - "roleDefinitionIdOrName": { - "type": "string", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "principalId": { - "type": "string", + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." } }, - "principalType": { + "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "AzureDiagnostics", + "Dedicated" ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "description": { + "workspaceResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "condition": { + "storageAccountResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "conditionVersion": { + "eventHubAuthorizationRuleResourceId": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "delegatedManagedIdentityResourceId": { + "eventHubName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } @@ -4464,126 +4007,155 @@ "name": { "type": "string", "metadata": { - "description": "Required. The name of the Public IP Address." + "description": "Required. Name of the Application Insights." } }, - "publicIpPrefixResourceId": { + "applicationType": { "type": "string", - "nullable": true, + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + "description": "Optional. Application type." } }, - "publicIPAllocationMethod": { + "workspaceResourceId": { "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], "metadata": { - "description": "Optional. The public IP address allocation method." + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." } }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", "allowedValues": [ - 1, - 2, - 3 + "Enabled", + "Disabled" ], "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." } }, - "publicIPAddressVersion": { + "publicNetworkAccessForQuery": { "type": "string", - "defaultValue": "IPv4", + "defaultValue": "Enabled", "allowedValues": [ - "IPv4", - "IPv6" + "Enabled", + "Disabled" ], "metadata": { - "description": "Optional. IP address version." + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." } }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], "metadata": { - "description": "Optional. The DNS settings of the public IP address." + "description": "Optional. Retention period in days." } }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, "metadata": { - "description": "Optional. The list of tags associated with the public IP address." + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." } }, - "lock": { - "$ref": "#/definitions/lockType", + "flowType": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." } }, - "skuName": { + "requestSource": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], + "nullable": true, "metadata": { - "description": "Optional. Name of a public IP address SKU." + "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." } }, - "skuTier": { + "kind": { "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], + "defaultValue": "", "metadata": { - "description": "Optional. Tier of a public IP address SKU." + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." } }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", + "immediatePurgeDataOn30Days": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + "description": "Optional. Purge data immediately after 30 days." } }, - "deleteOption": { + "ingestionMode": { "type": "string", "nullable": true, "allowedValues": [ - "Delete", - "Detach" + "ApplicationInsights", + "ApplicationInsightsWithDiagnosticSettings", + "LogAnalytics" ], "metadata": { - "description": "Optional. The delete option for the public IP address." + "description": "Optional. Indicates the flow of the ingestion." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, "roleAssignments": { @@ -4596,30 +4168,23 @@ "description": "Optional. Array of role assignments to create." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + "source": "Microsoft.Insights/components@2020-02-02#properties/tags" }, "description": "Optional. Tags of the resource." }, "nullable": true }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, "diagnosticSettings": { "type": "array", "items": { @@ -4641,15 +4206,14 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" } }, "resources": { @@ -4657,7 +4221,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -4673,51 +4237,38 @@ } } }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2025-01-01", + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "kind": "[parameters('kind')]", "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]", + "Flow_Type": "[parameters('flowType')]", + "Request_Source": "[parameters('requestSource')]", + "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", + "IngestionMode": "[parameters('ingestionMode')]" } }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { + "appInsights_roleAssignments": { "copy": { - "name": "publicIpAddress_roleAssignments", + "name": "appInsights_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -4728,17 +4279,31 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "publicIpAddress" + "appInsights" + ] + }, + "appInsights_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "appInsights" ] }, - "publicIpAddress_diagnosticSettings": { + "appInsights_diagnosticSettings": { "copy": { - "name": "publicIpAddress_diagnosticSettings", + "name": "appInsights_diagnosticSettings", "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -4769,45 +4334,142 @@ "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "publicIpAddress" + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5059808225314360251" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "appInsights" ] } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the public IP address was deployed into." + "description": "The name of the application insights component." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the public IP address." + "description": "The resource ID of the application insights component." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" }, - "resourceId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource ID of the public IP address." + "description": "The resource group the application insights component was deployed into." }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + "value": "[resourceGroup().name]" }, - "ipAddress": { + "applicationId": { "type": "string", "metadata": { - "description": "The public IP address of the public IP address resource." + "description": "The application ID of the application insights component." }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + "value": "[reference('appInsights').AppId]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" } } } @@ -4815,54 +4477,39 @@ } }, "outputs": { - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group the Azure Bastion was deployed into." + "description": "Resource ID of the Application Insights component." }, - "value": "[resourceGroup().name]" + "value": "[reference('appInsights').outputs.resourceId.value]" }, "name": { "type": "string", "metadata": { - "description": "The name the Azure Bastion." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID the Azure Bastion." + "description": "Name of the Application Insights component." }, - "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" + "value": "[reference('appInsights').outputs.name.value]" }, - "location": { + "connectionString": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('azureBastion', '2025-01-01', 'full').location]" - }, - "ipConfAzureBastionSubnet": { - "type": "object", - "metadata": { - "description": "The Public IPconfiguration object for the AzureBastionSubnet." + "description": "Connection string of the Application Insights component." }, - "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" + "value": "[reference('appInsights').outputs.connectionString.value]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" ] }, - "jumpboxVM": { - "condition": "[parameters('enablePrivateNetworking')]", + { + "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", + "name": "[take(format('module.data-collection-rule.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -4870,10 +4517,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[variables('jumpboxVmName')]" - }, - "location": { - "value": "[parameters('location')]" + "value": "[variables('dataCollectionRulesResourceName')]" }, "tags": { "value": "[parameters('tags')]" @@ -4881,3267 +4525,2547 @@ "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "computerName": { - "value": "[take(variables('jumpboxVmName'), 15)]" - }, - "osType": { - "value": "Windows" - }, - "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", - "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", - "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "patchMode": { - "value": "AutomaticByPlatform" - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "value": true - }, - "maintenanceConfigurationResourceId": { - "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" - }, - "enableAutomaticUpdates": { - "value": true - }, - "encryptionAtHost": { - "value": false - }, - "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", - "imageReference": { - "value": { - "publisher": "microsoft-dsvm", - "offer": "dsvm-win-2022", - "sku": "winserver-2022", - "version": "latest" - } + "location": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.location.value]" }, - "osDisk": { + "dataCollectionRuleProperties": { "value": { - "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", - "caching": "ReadWrite", - "createOption": "FromImage", - "deleteOption": "Delete", - "diskSizeGB": 128, - "managedDisk": { - "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" - } - } - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-{0}', variables('jumpboxVmName'))]", - "tags": "[parameters('tags')]", - "deleteOption": "Delete", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", - "ipConfigurations": [ + "kind": "Windows", + "dataSources": { + "performanceCounters": [ { - "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", - "subnetResourceId": "[reference('virtualNetwork').outputs.administrationSubnetResourceId.value]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Processes", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Handle Count", + "\\System\\System Up Time", + "\\System\\Context Switches/sec", + "\\System\\Processor Queue Length", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pages/sec", + "\\Memory\\Page Faults/sec", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors" + ], + "name": "perfCounterDataSource60" + } + ], + "windowsEventLogs": [ + { + "name": "SecurityAuditEvents", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" + ] } ] - } - ] - }, - "extensionAadJoinConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]", - "typeHandlerVersion": "1.0", - "settings": { - "mdmId": "" - } - } - }, - "extensionAntiMalwareConfig": { - "value": { - "enabled": true, - "settings": { - "AntimalwareEnabled": "true", - "Exclusions": {}, - "RealtimeProtectionEnabled": "true", - "ScheduledScanSettings": { - "day": "7", - "isEnabled": "true", - "scanType": "Quick", - "time": "120" - } }, - "tags": "[parameters('tags')]" - } - }, - "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", - "extensionNetworkWatcherAgentConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]" - } - } - }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]", + "name": "[variables('dcrLogAnalyticsDestinationName')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Microsoft-Perf" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Perf" + }, + { + "streams": [ + "Microsoft-Event" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Event" + } + ] + } + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17174537341033050778" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." + "version": "0.42.1.51946", + "templateHash": "6345941552527061617" + } }, - "definitions": { - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "diffDiskSettings": { - "type": "object", - "properties": { - "placement": { - "type": "string", - "allowedValues": [ - "CacheDisk", - "NvmeDisk", - "ResourceDisk" - ], - "metadata": { - "description": "Required. Specifies the ephemeral disk placement for the operating system disk." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - }, + "parameters": { + "name": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type describing an OS disk." + "description": "Name of the data collection rule." } }, - "dataDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." - } - }, - "diskIOPSReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." - } - }, - "diskMBpsReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" - }, - "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." - }, - "nullable": true - } - }, + "location": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type describing a data disk." - } - }, - "publicKeyType": { - "type": "object", - "properties": { - "keyData": { - "type": "string", - "metadata": { - "description": "Required. Specifies the SSH public key data used to authenticate through ssh." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." - } - } + "description": "Azure region for the resource." } }, - "nicConfigurationType": { + "tags": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the NIC configuration." - } - }, - "nicSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The suffix to append to the NIC name." - } - }, - "enableIPForwarding": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify what happens to the network interface when the VM is deleted." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "metadata": { - "description": "Required. The IP configurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags of the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, + "defaultValue": {}, "metadata": { - "__bicep_export!": true, - "description": "The type for the NIC configuration." + "description": "Tags to apply to the resource." } }, - "imageReferenceType": { - "type": "object", - "properties": { - "communityGalleryImageId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." - } - }, - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the image reference." - } - }, - "offer": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The image publisher." - } - }, - "sku": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The SKU of the image." - } - }, - "version": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." - } - }, - "sharedGalleryImageId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." - } - } - }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_export!": true, - "description": "The type describing the image reference." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "planType": { + "dataCollectionRuleProperties": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the plan." - } - }, - "product": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the product of the image from the marketplace." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher ID." - } - }, - "promotionCode": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The promotion code." - } - } - }, "metadata": { - "__bicep_export!": true, - "description": "Specifies information about the marketplace image used to create the virtual machine." + "description": "Properties block for the data collection rule." } - }, - "autoShutDownConfigType": { - "type": "object", + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.data-collection-rule.{0}', parameters('name')), 64)]", "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the auto shutdown configuration." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "timeZone": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "dataCollectionRuleProperties": { + "value": "[parameters('dataCollectionRuleProperties')]" } }, - "dailyRecurrenceTime": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The time of day the schedule will occur." - } - }, - "notificationSettings": { - "type": "object", - "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the notification settings." - } - }, - "emailRecipient": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." - } + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2441324888126124697" }, - "notificationLocale": { - "type": "string", - "nullable": true, + "name": "Data Collection Rules", + "description": "This module deploys a Data Collection Rule." + }, + "definitions": { + "dataCollectionRulePropertiesType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Linux": { + "$ref": "#/definitions/linuxDcrPropertiesType" + }, + "Windows": { + "$ref": "#/definitions/windowsDcrPropertiesType" + }, + "All": { + "$ref": "#/definitions/allPlatformsDcrPropertiesType" + }, + "AgentSettings": { + "$ref": "#/definitions/agentSettingsDcrPropertiesType" + }, + "Direct": { + "$ref": "#/definitions/directDcrPropertiesType" + }, + "WorkspaceTransforms": { + "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" + }, + "PlatformTelemetry": { + "$ref": "#/definitions/platformTelemetryDcrPropertiesType" + } + } + }, "metadata": { - "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + "__bicep_export!": true, + "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." } }, - "webhookUrl": { - "type": "string", - "nullable": true, + "linuxDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Linux" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, "metadata": { - "description": "Optional. The webhook URL to which the notification will be sent." + "description": "The type for the properties of the 'Linux' data collection rule." } }, - "timeInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The time in minutes before shutdown to send notifications." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the schedule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the configuration profile." - } - }, - "vaultSecretGroupType": { - "type": "object", - "properties": { - "sourceVault": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." - } - }, - "vaultCertificates": { - "type": "array", - "items": { - "type": "object", - "properties": { - "certificateStore": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + "windowsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Windows" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } } }, - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of key vault references in SourceVault which contain certificates." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the set of certificates that should be installed onto the virtual machine." - } - }, - "vmGalleryApplicationType": { - "type": "object", - "properties": { - "packageReferenceId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." - } - }, - "configurationReference": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." - } - }, - "order": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the order in which the packages have to be installed." - } - }, - "tags": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies a passthrough value for more generic context." - } - }, - "treatFailureAsDeploymentFailure": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the gallery application that should be made available to the VM/VMSS." - } - }, - "additionalUnattendContentType": { - "type": "object", - "properties": { - "settingName": { - "type": "string", - "allowedValues": [ - "AutoLogon", - "FirstLogonCommands" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the name of the setting to which the content applies." - } - }, - "content": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." - } - }, - "winRMListenerType": { - "type": "object", - "properties": { - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "Http", - "Https" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the protocol of WinRM listener." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing a Windows Remote Management listener." - } - }, - "nicConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NIC configuration." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "Required. List of IP configurations of the NIC configuration." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the network interface configuration output." - } - }, - "extensionCustomScriptConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." - } - }, - "typeHandlerVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + "description": "The type for the properties of the 'Windows' data collection rule." } }, - "fileUris": { - "type": "array", - "items": { - "type": "string" + "allPlatformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." + "description": "The type for the properties of the data collection rule of the kind 'All'." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "protectedSettings": { - "type": "secureObject", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, + }, + "agentSettingsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AgentSettings" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "agentSettings": { + "$ref": "#/definitions/agentSettingsType", + "metadata": { + "description": "Required. Agent settings used to modify agent behavior on a given host." + } + } + }, "metadata": { - "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." + "description": "The type for the properties of the 'AgentSettings' data collection rule." } }, - "storageAccountName": { - "type": "string", - "nullable": true, + "agentSettingsType": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agentSettingType" + }, + "metadata": { + "description": "Required. All the settings that are applicable to the logs agent (AMA)." + } + } + }, "metadata": { - "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." + "description": "The type for the agent settings." } }, - "storageAccountKey": { - "type": "string", - "nullable": true, + "agentSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "MaxDiskQuotaInMB", + "UseTimeReceivedForForwardedEvents" + ], + "metadata": { + "description": "Required. The name of the agent setting." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the agent setting." + } + } + }, "metadata": { - "description": "Optional. The access key of the storage account." + "description": "The type for the (single) agent setting." } }, - "managedIdentityResourceId": { - "type": "string", - "nullable": true, + "directDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Direct" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Required. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, "metadata": { - "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." + "description": "The type for the properties of the 'Direct' data collection rule." } }, - "fileUris": { - "type": "array", - "items": { - "type": "string" + "workspaceTransformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "WorkspaceTransforms" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. URLs for files to be downloaded." + "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "supressFailures": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a 'CustomScriptExtension' extension." - } - }, - "_1.applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." + "platformTelemetryDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "PlatformTelemetry" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "dataSources": { + "type": "object", + "properties": { + "platformTelemetry": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + }, + "description": "Required. The list of platform telemetry configurations." + } } }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "destinations": { + "type": "object", + "properties": { + "logAnalytics": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + }, + "description": "Optional. The list of Log Analytics destinations." + }, + "nullable": true + }, + "storageAccounts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + }, + "description": "Optional. The list of Storage Account destinations." + }, + "nullable": true + }, + "eventHubs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + }, + "description": "Optional. The list of Event Hub destinations." + }, + "nullable": true } + }, + "metadata": { + "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." } } }, - "nullable": true, "metadata": { - "description": "Optional. Backend addresses." + "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "description": "Optional. A reference to backendAddressPool resource." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "backendPort": { - "type": "int", - "nullable": true, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the data collection rule. The name is case insensitive." } }, - "enableTcpReset": { - "type": "bool", - "nullable": true, + "dataCollectionRuleProperties": { + "$ref": "#/definitions/dataCollectionRulePropertiesType", "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + "description": "Required. The kind of data collection rule." } }, - "frontendIPConfiguration": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. A reference to frontend IP addresses." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "frontendPort": { - "type": "int", - "nullable": true, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + "description": "Optional. Location for all Resources." } }, - "frontendPortRangeStart": { - "type": "int", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + "description": "Optional. The lock settings of the service." } }, - "frontendPortRangeEnd": { - "type": "int", + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + "description": "Optional. The managed identity definition for this resource." } }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." + "description": "Optional. Array of role assignments to create." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_2.ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", + }, + "tags": { + "type": "object", "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true } }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_2.dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_2.ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_3.diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } - } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", + "enableReferencedModulesTelemetry": false }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + }, + "dataCollectionRule": { + "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('dataCollectionRuleProperties').kind]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRuleAll": { + "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRule_conditionalScopeLock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", + "lock": { + "value": "[parameters('lock')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2876136109547890997" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "dataCollectionRuleName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + } + } + }, + "resources": { + "dataCollectionRule": { + "existing": true, + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dataCollectionRuleName')]" + }, + "dataCollectionRule_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + }, + "dataCollectionRule_roleAssignments": { + "copy": { + "name": "dataCollectionRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", + "name": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14634305923902101494" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource." + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dataCollectionRule was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" + }, + "endpoints": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", + "output": true + }, + "description": "The endpoints of the dataCollectionRule, if created." + }, + "nullable": true, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" + }, + "immutableId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The ImmutableId of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" + } + } + } } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the data collection rule." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.insights.data-collection-rule.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "_3.lockType": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the data collection rule." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.insights.data-collection-rule.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "addressPrefixes": { + "value": [ + "10.0.0.0/8" + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "resourceSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "10323079586505814920" + } + }, + "definitions": { + "subnetOutputType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "The name of the subnet." } }, - "kind": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the subnet." + } + }, + "nsgName": { "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "The name of the associated NSG, if any." } }, - "notes": { + "nsgResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "The resource ID of the associated NSG, if any." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "__bicep_export!": true, + "description": "Subnet output type" } }, - "_3.roleAssignmentType": { + "subnetType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Required. The name of the subnet." } }, - "roleDefinitionIdOrName": { - "type": "string", + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Required. Address prefixes for the subnet." } }, - "principalId": { + "delegation": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. Delegation for the subnet." } }, - "principalType": { + "privateEndpointNetworkPolicies": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. Private endpoint network policies." } }, - "conditionVersion": { + "privateLinkServiceNetworkPolicies": { "type": "string", "allowedValues": [ - "2.0" + "Disabled", + "Enabled" ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Private link service network policies." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_4.publicIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", + "networkSecurityGroup": { + "$ref": "#/definitions/networkSecurityGroupType", "nullable": true, "metadata": { - "description": "Optional. The name of the Public IP Address." + "description": "Optional. NSG configuration for the subnet." } }, - "publicIPAddressResourceId": { + "routeTableResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the public IP address." + "description": "Optional. Route table resource ID." } }, - "diagnosticSettings": { + "serviceEndpointPolicies": { "type": "array", "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" + "type": "object" }, "nullable": true, "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." + "description": "Optional. Service endpoint policies." } }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout in minutes." - } - }, - "lock": { - "$ref": "#/definitions/_3.lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the public IP address." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "ddosSettings": { - "$ref": "#/definitions/_2.ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "dnsSettings": { - "$ref": "#/definitions/_2.dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address version." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIpNameSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name suffix of the public IP address resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU tier of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], - "nullable": true, - "metadata": { - "description": "Optional. The zones of the public IP address." - } - }, - "ipTags": { + "serviceEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/_2.ipTagType" + "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. The list of tags associated with the public IP address." + "description": "Optional. Service endpoints to enable." } }, - "enableTelemetry": { + "defaultOutboundAccess": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." + "description": "Optional. Disable default outbound connectivity." } } }, "metadata": { - "description": "The type for the public IP address configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } + "__bicep_export!": true, + "description": "Subnet configuration type" } }, - "diagnosticSettingFullType": { + "networkSecurityGroupType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "description": "Required. The name of the NSG." } }, - "logCategoriesAndGroups": { + "securityRules": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "type": "object" }, - "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. Security rules for the NSG." } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + }, + "metadata": { + "__bicep_export!": true, + "description": "NSG configuration type" + } + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Azure region for the resource." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Address prefixes for the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "defaultValue": [ + { + "name": "backend", + "addressPrefixes": [ + "10.0.0.0/27" + ], + "networkSecurityGroup": { + "name": "nsg-backend", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + ] } }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + { + "name": "webserverfarm", + "addressPrefixes": [ + "10.0.4.0/27" ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "delegation": "Microsoft.Web/serverfarms", + "privateEndpointNetworkPolicies": "Enabled", + "privateLinkServiceNetworkPolicies": "Enabled", + "networkSecurityGroup": { + "name": "nsg-webserverfarm", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] } }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + { + "name": "administration", + "addressPrefixes": [ + "10.0.0.32/27" + ], + "networkSecurityGroup": { + "name": "nsg-administration", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] } }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + { + "name": "AzureBastionSubnet", + "addressPrefixes": [ + "10.0.0.64/26" + ], + "networkSecurityGroup": { + "name": "nsg-bastion", + "securityRules": [ + { + "name": "AllowGatewayManager", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2702, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "GatewayManager", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowHttpsInBound", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2703, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowSshRdpOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 100, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AllowAzureCloudOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 110, + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "AzureCloud" + } + } + ] } } - }, + ], "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Subnet configurations." } }, - "ipConfigurationType": { + "tags": { "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resources." + } + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Log Analytics Workspace for diagnostics." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceSuffix": { + "type": "string", + "metadata": { + "description": "Suffix for resource naming." + } + } + }, + "variables": { + "name": "[format('vnet-{0}', parameters('solutionName'))]" + }, + "resources": { + "nsgs": { + "copy": { + "name": "nsgs", + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer backend address pools." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application security groups." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" }, - "nullable": true, - "metadata": { - "description": "Optional. The application gateway backend address pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The gateway load balancer settings." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.inboundNatRuleType" + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer inbound NAT rules." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address version." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.virtualNetworkTapType" + "securityRules": { + "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The virtual network taps." - } - }, - "pipConfiguration": { - "$ref": "#/definitions/_4.publicIPConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The public IP address configuration." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" + "tags": { + "value": "[parameters('tags')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, - "tags": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7311263652424030280" }, - "description": "Optional. The tags of the public IP address." + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG)." }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "description": "The type for the IP configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "definitions": { + "securityRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "properties": { + "type": "object", + "properties": { + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the security rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 4096, + "metadata": { + "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "metadata": { + "description": "Required. The properties of the security rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a security rule." + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "description": "The type for the network interface IP configuration output.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "securityRules": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" + }, + "description": "Optional. Tags of the NSG resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(coalesce(parameters('securityRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "properties": { + "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", + "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", + "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", + "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", + "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", + "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", + "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", + "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", + "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", + "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", + "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", + "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", + "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", + "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", + "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { + "copy": { + "name": "networkSecurityGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } }, - "subResourceType": { - "type": "object", + "virtualNetwork": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." - }, - "nullable": true - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" - }, - "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." - }, - "nullable": true - }, - "plan": { - "$ref": "#/definitions/planType", - "nullable": true, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "type": "array", - "items": { - "$ref": "#/definitions/dataDiskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "hibernationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables hibernation capability on the VM." - } - }, - "adminUsername": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." - } - }, - "userData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "items": { - "$ref": "#/definitions/vaultSecretGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "evictionPolicy": { - "type": "string", - "defaultValue": "Deallocate", - "allowedValues": [ - "Deallocate", - "Delete" - ], - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "publicKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/publicKeyType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "galleryApplications": { - "type": "array", - "items": { - "$ref": "#/definitions/vmGalleryApplicationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." - } - }, - "availabilityZone": { - "type": "int", - "allowedValues": [ - -1, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." - } - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationType" - }, - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Recovery service vault name to add VMs to backup." - } - }, - "backupVaultResourceGroup": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." - } - }, - "backupPolicyName": { - "type": "string", - "defaultValue": "DefaultPolicy", - "metadata": { - "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." - } - }, - "autoShutdownConfig": { - "$ref": "#/definitions/autoShutDownConfigType", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for auto-shutdown." - } - }, - "maintenanceConfigurationResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The resource Id of a maintenance configuration for this VM." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAntiMalwareConfig": { - "type": "object", - "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", - "metadata": { - "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionMonitoringAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "dataCollectionRuleAssociations": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionDependencyAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNetworkWatcherAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "$ref": "#/definitions/extensionCustomScriptConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionHostPoolRegistration": { - "type": "secureObject", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "extensionGuestConfigurationExtension": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "guestConfiguration": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." - } - }, - "extensionGuestConfigurationExtensionProtectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "disablePasswordAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether password authentication should be disabled." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "enableHotpatching": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "items": { - "$ref": "#/definitions/additionalUnattendContentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRMListeners": { - "type": "array", - "items": { - "$ref": "#/definitions/winRMListenerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - }, - "capacityReservationGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." - } - }, - "networkAccessPolicy": { - "type": "string", - "defaultValue": "DenyAll", - "allowedValues": [ - "AllowAll", - "AllowPrivate", - "DenyAll" - ], - "metadata": { - "description": "Optional. Policy for accessing the disk via network." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Policy for controlling export on the disk." - } - } - }, - "variables": { - "copy": [ - { - "name": "publicKeysFormatted", - "count": "[length(parameters('publicKeys'))]", - "input": { - "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", - "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" - } - }, - { - "name": "additionalUnattendContentFormatted", - "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", - "input": { - "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", - "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", - "componentName": "Microsoft-Windows-Shell-Setup", - "passName": "OobeSystem" - } - }, - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "linuxConfiguration": { - "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", - "ssh": { - "publicKeys": "[variables('publicKeysFormatted')]" - }, - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" - }, - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", - "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", - "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", - "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", - "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", - "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", - "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", - "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", - "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", - "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", - "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", - "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", - "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" - }, - "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", - "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "managedDataDisks": { - "copy": { - "name": "managedDataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" - }, - "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", - "type": "Microsoft.Compute/disks", - "apiVersion": "2025-01-02", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", - "location": "[parameters('location')]", - "sku": { - "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" - }, - "properties": { - "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", - "creationData": { - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" - }, - "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", - "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "networkAccessPolicy": "[parameters('networkAccessPolicy')]" - }, - "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", - "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", - "plan": "[parameters('plan')]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", - "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", - "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", - "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", - "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", - "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", - "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", - "osType": "[parameters('osType')]", - "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", - "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", - "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", - "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", - "managedDisk": { - "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", - "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", - "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", - "hibernationEnabled": "[parameters('hibernationEnabled')]" - }, - "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" - } - } - ] - }, - "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", - "licenseType": "[parameters('licenseType')]", - "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" - }, - "dependsOn": [ - "managedDataDisks", - "vm_nic" - ] - }, - "vm_configurationAssignment": { - "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", - "type": "Microsoft.Maintenance/configurationAssignments", - "apiVersion": "2023-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[format('{0}assignment', parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", - "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_autoShutdownConfiguration": { - "condition": "[not(empty(parameters('autoShutdownConfig')))]", - "type": "Microsoft.DevTestLab/schedules", - "apiVersion": "2018-09-15", - "name": "[format('shutdown-computevm-{0}', parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", - "properties": { - "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", - "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "taskType": "ComputeVmShutdownTask", - "dailyRecurrence": { - "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" - }, - "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", - "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_dataCollectionRuleAssociations": { - "copy": { - "name": "vm_dataCollectionRuleAssociations", - "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" - }, - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Insights/dataCollectionRuleAssociations", - "apiVersion": "2024-03-11", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", - "properties": { - "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "cseIdentity": { - "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", - "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" - }, - "AzureWindowsBaseline": { - "condition": "[not(empty(parameters('guestConfiguration')))]", - "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", - "apiVersion": "2024-04-05", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", - "location": "[parameters('location')]", - "properties": { - "guestConfiguration": "[parameters('guestConfiguration')]" - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - }, - "vm_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_roleAssignments": { - "copy": { - "name": "vm_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" - }, - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableIPForwarding": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" - }, - "enableAcceleratedNetworking": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" - }, - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" - }, - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "lock": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "addressPrefixes": { + "value": "[parameters('addressPrefixes')]" + }, + "subnets": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('subnets'))]", + "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "name": "vnetDiagnostics", + "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs", + "enabled": true + } + ], + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -8151,490 +7075,291 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "5982155361487304817" - } + "templateHash": "11272001757446231867" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet)." }, "definitions": { - "publicIPConfigurationType": { + "peeringType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Public IP Address." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." } }, - "publicIPAddressResourceId": { + "remoteVirtualNetworkResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The resource ID of the public IP address." + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, + "allowForwardedTraffic": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." } }, - "location": { - "type": "string", + "allowGatewayTransit": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The idle timeout in minutes." + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." } }, - "lock": { - "$ref": "#/definitions/lockType", + "allowVirtualNetworkAccess": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The lock settings of the public IP address." + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." } }, - "idleTimeoutInMinutes": { - "type": "int", + "doNotVerifyRemoteGateways": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The idle timeout of the public IP address." + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." } }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", + "useRemoteGateways": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." } }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", + "remotePeeringEnabled": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The DNS settings of the public IP address." + "description": "Optional. Deploy the outbound and the inbound peering." } }, - "publicIPAddressVersion": { + "remotePeeringName": { "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], "nullable": true, "metadata": { - "description": "Optional. The public IP address version." + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." } }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], + "remotePeeringAllowForwardedTraffic": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The public IP address allocation method." + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." } }, - "publicIpPrefixResourceId": { - "type": "string", + "remotePeeringAllowGatewayTransit": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." } }, - "publicIpNameSuffix": { - "type": "string", + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name suffix of the public IP address resource." + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." } }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], + "remotePeeringUseRemoteGateways": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU tier of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], - "nullable": true, - "metadata": { - "description": "Optional. The zones of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for the public IP address configuration." + "__bicep_export!": true } }, - "ipConfigurationType": { + "subnetType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, "metadata": { - "description": "Optional. The private IP address allocation method." + "description": "Required. The Name of the subnet resource." } }, - "privateIPAddress": { + "addressPrefix": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." } }, - "loadBalancerBackendAddressPools": { + "addressPrefixes": { "type": "array", "items": { - "$ref": "#/definitions/backendAddressPoolType" + "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. The load balancer backend address pools." + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." } }, - "applicationSecurityGroups": { + "ipamPoolPrefixAllocations": { "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, + "prefixItems": [ + { + "type": "object", + "properties": { + "pool": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + } + }, + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + }, + "numberOfIpAddresses": { + "type": "string", + "metadata": { + "description": "Required. Number of IP addresses allocated from the pool." + } + } + } + } + ], + "items": false, "nullable": true, "metadata": { - "description": "Optional. The application security groups." + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." } }, - "applicationGatewayBackendAddressPools": { + "applicationGatewayIPConfigurations": { "type": "array", "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + "type": "object" }, "nullable": true, "metadata": { - "description": "Optional. The application gateway backend address pools." + "description": "Optional. Application gateway IP configurations of virtual network resource." } }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", + "delegation": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The gateway load balancer settings." + "description": "Optional. The delegation to enable on the subnet." } }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, + "natGatewayResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The load balancer inbound NAT rules." + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." } }, - "privateIPAddressVersion": { + "networkSecurityGroupResourceId": { "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], "nullable": true, "metadata": { - "description": "Optional. The private IP address version." + "description": "Optional. The resource ID of the network security group to assign to the subnet." } }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], "nullable": true, "metadata": { - "description": "Optional. The virtual network taps." + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." } }, - "pipConfiguration": { - "$ref": "#/definitions/publicIPConfigurationType", + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], "nullable": true, "metadata": { - "description": "Optional. The public IP address configuration." + "description": "Optional. enable or disable apply network policies on private link service in the subnet." } }, - "diagnosticSettings": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." + "$ref": "#/definitions/roleAssignmentType" }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the IP configuration." - } - }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the backend address pool." + "description": "Optional. Array of role assignments to create." } }, - "name": { + "routeTableResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + "description": "Optional. The resource ID of the route table to assign to the subnet." } }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" }, "nullable": true, "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." + "description": "Optional. An array of service endpoint policies." } }, - "name": { - "type": "string", + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. The name of the backend address pool." + "description": "Optional. The service endpoints to enable on the subnet." } }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, + "defaultOutboundAccess": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." } }, - "protectionMode": { + "sharingScope": { "type": "string", "allowedValues": [ - "Enabled" + "DelegatedServices", + "Tenant" ], + "nullable": true, "metadata": { - "description": "Required. The DDoS protection policy customizations." + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } + "__bicep_export!": true } }, "diagnosticSettingFullType": { @@ -8755,295 +7480,98 @@ "metadata": { "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" } } }, - "dnsSettingsType": { + "lockType": { "type": "object", "properties": { - "domainNameLabel": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + "description": "Optional. Specify the name of lock." } }, - "domainNameLabelScope": { + "kind": { "type": "string", "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" + "CanNotDelete", + "None", + "ReadOnly" ], "nullable": true, "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + "description": "Optional. Specify the type of lock." } }, - "reverseFqdn": { + "notes": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } }, - "inboundNatRuleType": { + "roleAssignmentType": { "type": "object", "properties": { - "id": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "name": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, + "principalId": { + "type": "string", "metadata": { - "description": "Optional. Properties of the inbound NAT rule." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { + }, + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, "metadata": { - "description": "Required. The IP tag type." + "description": "Optional. The principal type of the assigned principal ID." } }, - "tag": { + "description": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The IP tag." + "description": "Optional. The description of the role assignment." } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { + }, + "condition": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { + "conditionVersion": { "type": "string", "allowedValues": [ "2.0" @@ -9064,127 +7592,106 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" } } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, + } + }, + "parameters": { + "name": { + "type": "string", "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } + "description": "Required. The name of the Virtual Network (vNet)." } }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } + "description": "Optional. Location for all resources." } - } - }, - "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" }, - "ipConfigurations": { + "addressPrefixes": { "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." } }, - "location": { + "ipamPoolNumberOfIpAddresses": { "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." } }, - "tags": { - "type": "object", + "virtualNetworkBgpCommunity": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. The BGP community associated with the virtual network." } }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } }, "dnsServers": { "type": "array", "items": { "type": "string" }, - "defaultValue": [] + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } }, - "enableTelemetry": { + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." } }, - "networkSecurityGroupResourceId": { + "vnetEncryptionEnforcement": { "type": "string", - "defaultValue": "", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." } }, "diagnosticSettings": { @@ -9197,6 +7704,13 @@ "description": "Optional. The diagnostic settings of the service." } }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, "roleAssignments": { "type": "array", "items": { @@ -9206,74 +7720,243 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + }, + "enablePrivateEndpointVNetPolicies": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Basic", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "networkInterface_publicIPAddresses": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]", + "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 }, - "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" }, - "diagnosticSettings": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" }, - "location": { - "value": "[parameters('location')]" + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" }, - "lock": { - "value": "[parameters('lock')]" + "ipamPoolPrefixAllocations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" }, - "idleTimeoutInMinutes": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" }, - "ddosSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" }, - "dnsSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" }, - "publicIPAddressVersion": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" }, - "publicIPAllocationMethod": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" }, - "publicIpPrefixResourceId": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" }, "roleAssignments": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" }, - "skuName": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" }, - "skuTier": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" }, - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" }, - "availabilityZones": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" }, - "enableTelemetry": { - "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" }, - "ipTags": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -9283,180 +7966,21 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5349747633189946992" + "version": "0.41.2.15936", + "templateHash": "13992200806189615656" }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." }, "definitions": { - "diagnosticSettingFullType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, "roleDefinitionIdOrName": { @@ -9520,7 +8044,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" } } } @@ -9529,171 +8053,151 @@ "name": { "type": "string", "metadata": { - "description": "Required. The name of the Public IP Address." + "description": "Required. The Name of the subnet resource." } }, - "publicIpPrefixResourceId": { + "virtualNetworkName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." } }, - "publicIPAllocationMethod": { + "addressPrefix": { "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" - }, - "description": "Optional. The public IP address allocation method." - }, - "defaultValue": "Static" + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } }, - "availabilityZones": { + "ipamPoolPrefixAllocations": { "type": "array", "items": { - "type": "int" + "type": "object" }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], + "nullable": true, "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." } }, - "publicIPAddressVersion": { + "networkSecurityGroupResourceId": { "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" - }, - "description": "Optional. IP address version." - }, - "defaultValue": "IPv4" + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } }, - "dnsSettings": { - "type": "object", + "routeTableResourceId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" - }, - "description": "Optional. The DNS settings of the public IP address." - }, - "nullable": true + "description": "Optional. The resource ID of the route table to assign to the subnet." + } }, - "ipTags": { + "serviceEndpoints": { "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" - }, - "description": "Optional. The list of tags associated with the public IP address." + "items": { + "type": "string" }, - "nullable": true - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. The service endpoints to enable on the subnet." } }, - "skuName": { + "delegation": { "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" - }, - "description": "Optional. Name of a public IP address SKU." - }, - "defaultValue": "Standard" + "description": "Optional. The delegation to enable on the subnet." + } }, - "skuTier": { + "natGatewayResourceId": { "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" - }, - "description": "Optional. Tier of a public IP address SKU." - }, - "defaultValue": "Regional" - }, - "ddosSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" - }, - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - }, - "nullable": true + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } }, - "deleteOption": { + "privateEndpointNetworkPolicies": { "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" - }, - "description": "Optional. The delete option for the public IP address." - }, - "nullable": true + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } }, - "location": { + "privateLinkServiceNetworkPolicies": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." } }, - "roleAssignments": { + "addressPrefixes": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." } }, - "enableTelemetry": { + "defaultOutboundAccess": { "type": "bool", - "defaultValue": true, + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." } }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, "metadata": { - "description": "Optional. The idle timeout of the public IP address." + "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." } }, - "tags": { - "type": "object", + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true + "description": "Optional. Application gateway IP configurations of virtual network resource." + } }, - "diagnosticSettings": { + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, @@ -9707,15 +8211,11 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { @@ -9723,7 +8223,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -9739,51 +8239,50 @@ } } }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" - } + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "publicIpAddress" - ] + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + } }, - "publicIpAddress_roleAssignments": { + "subnet_roleAssignments": { "copy": { - "name": "publicIpAddress_roleAssignments", + "name": "subnet_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -9794,48 +8293,7 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" + "subnet" ] } }, @@ -9843,1409 +8301,603 @@ "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the public IP address was deployed into." + "description": "The resource group the virtual network peering was deployed into." }, "value": "[resourceGroup().name]" }, "name": { "type": "string", "metadata": { - "description": "The name of the public IP address." + "description": "The name of the virtual network peering." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the public IP address." + "description": "The resource ID of the virtual network peering." }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" }, - "ipAddress": { + "addressPrefix": { "type": "string", "metadata": { - "description": "The public IP address of the public IP address resource." + "description": "The address prefix for the subnet." }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" }, - "location": { - "type": "string", + "addressPrefixes": { + "type": "array", "metadata": { - "description": "The location the resource was deployed into." + "description": "List of address prefixes for the subnet." }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "metadata": { + "description": "The IPAM pool prefix allocations for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" } } } - } + }, + "dependsOn": [ + "virtualNetwork" + ] }, - "networkInterface": { + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" + "localVnetName": { + "value": "[parameters('name')]" }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" }, - "dnsServers": { - "value": "[parameters('dnsServers')]" + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" }, - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" }, - "lock": { - "value": "[parameters('lock')]" + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": { - "value": "[parameters('roleAssignments')]" + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "272838238520810437" + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" }, - "name": "Network Interface", - "description": "This module deploys a Network Interface." + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." }, - "definitions": { - "networkInterfaceIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of load balancer backend address pools." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of references of LoadBalancerInboundNatRules." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the IP configuration is included." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Application Gateway Backend Address Pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The reference to gateway load balancer frontend IP." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Virtual Network Taps." - } - } - }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "__bicep_export!": true, - "description": "The resource ID of the deployed resource." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, + "localVnetName": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for a backend address pool." + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." } }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, + "remoteVirtualNetworkResourceId": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for the application security group." + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." } }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_export!": true, - "description": "The type for the application gateway backend address pool." + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." } }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_export!": true, - "description": "The type for the sub resource." + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." } }, - "inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_export!": true, - "description": "The type for the inbound NAT rule." + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." } }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network tap." + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." } }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for the network interface IP configuration output." - } + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + "resourceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } + "description": "The resource ID of the virtual network peering." }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." }, "parameters": { "name": { "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Required. The name of the network interface." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, - "location": { + "localVnetName": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." } }, - "tags": { - "type": "object", + "remoteVirtualNetworkResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } }, - "enableTelemetry": { + "allowForwardedTraffic": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." } }, - "enableIPForwarding": { + "allowGatewayTransit": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." } }, - "enableAcceleratedNetworking": { + "allowVirtualNetworkAccess": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], + "defaultValue": true, "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." } }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." } }, - "disableTcpStateTracking": { + "useRemoteGateways": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationType" - }, - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, - "resources": { - "publicIp": { - "copy": { - "name": "publicIp", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", - "existing": true, - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2024-05-01", - "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", - "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", - "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", - "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", - "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", - "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", - "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", - "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] } - }, + ], "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed resource." + "description": "The resource group the virtual network peering was deployed into." }, "value": "[resourceGroup().name]" }, - "location": { + "name": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The name of the virtual network peering." }, - "value": "[reference('networkInterface', '2024-05-01', 'full').location]" + "value": "[parameters('name')]" }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, + "resourceId": { + "type": "string", "metadata": { - "description": "The list of IP configurations of the network interface." + "description": "The resource ID of the virtual network peering." }, - "copy": { - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", - "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", - "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" - } - } + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" } } } }, "dependsOn": [ - "networkInterface_publicIPAddresses" + "virtualNetwork", + "virtualNetwork_subnets" ] } }, "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the network interface." + "description": "The name of the virtual network." }, - "value": "[reference('networkInterface').outputs.name.value]" + "value": "[parameters('name')]" }, - "ipConfigurations": { + "subnetNames": { "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, "metadata": { - "description": "The list of IP configurations of the network interface." + "description": "The names of the deployed subnets." }, - "value": "[reference('networkInterface').outputs.ipConfigurations.value]" - } - } - } - } - }, - "vm_domainJoinExtension": { - "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { + "subnetResourceIds": { "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + "description": "The resource IDs of the deployed subnets." }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('extension', '2024-11-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" } } } }, "dependsOn": [ - "vm" + "nsgs" ] + } + }, + "outputs": { + "name": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.name.value]" + }, + "resourceId": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetOutputType" + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex()].name]", + "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", + "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", + "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" + } + } + }, + "backendSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" + }, + "webserverfarmSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" + }, + "administrationSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" + }, + "bastionSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.bastion-host.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('bastionHostName')]" + }, + "skuName": { + "value": "Standard" + }, + "location": { + "value": "[parameters('location')]" + }, + "virtualNetworkResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": { + "name": "[format('pip-{0}', variables('bastionHostName'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9712719642210419114" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the Bastion host." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "metadata": { + "description": "SKU name for the Bastion host." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the virtual network hosting the AzureBastionSubnet." + } + }, + "diagnosticSettings": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings to apply to the Bastion host." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", + "publicIPAddressObject": { + "type": "object", + "metadata": { + "description": "Public IP configuration object for the Bastion host." + } + } + }, + "resources": { + "bastionHost": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.network.bastion-host.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" + "value": "[parameters('name')]" }, "location": { "value": "[parameters('location')]" }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" + "skuName": { + "value": "[parameters('skuName')]" }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + "virtualNetworkResourceId": { + "value": "[parameters('virtualNetworkResourceId')]" }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + "tags": { + "value": "[parameters('tags')]" }, - "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + "publicIPAddressObject": { + "value": "[parameters('publicIPAddressObject')]" } }, "template": { @@ -11255,9488 +8907,950 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" + "version": "0.39.26.7824", + "templateHash": "7741601918225805390" }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host." }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", + "definitions": { + "publicIPAddressObjectType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for the Public IP resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create for the Public IP resource." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the Public IP module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Idle timeout in minutes for the Public IP resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to apply to the Public IP resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the Public IP resource." + } + } + }, "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "__bicep_export!": true, + "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." } }, - "forceUpdateTag": { - "type": "string", - "nullable": true, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } } }, - "settings": { + "diagnosticSettingFullType": { "type": "object", - "nullable": true, + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, "metadata": { - "description": "Optional. Any object that contains the extension specific settings." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "supressFailures": { - "type": "bool", - "defaultValue": false, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } } }, - "enableAutomaticUpgrade": { - "type": "bool", + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } } }, - "tags": { + "lockType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } }, - "description": "Optional. Tags of the resource." + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "nullable": true + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "protectedSettingsFromKeyVault": { + "roleAssignmentType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } } }, - "outputs": { + "parameters": { "name": { "type": "string", "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "description": "Required. Name of the Azure Bastion resource." + } }, - "resourceGroupName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" + "description": "Optional. Location for all resources." + } }, - "location": { + "virtualNetworkResourceId": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_domainJoinExtension" - ] - }, - "vm_microsoftAntiMalwareExtension": { - "condition": "[parameters('extensionAntiMalwareConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": { - "value": "IaaSAntimalware" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" + "description": "Required. Shared services Virtual Network resource Id." + } }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { + "bastionSubnetPublicIpResourceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." } }, - "name": { - "type": "string", + "publicIPAddressObject": { + "$ref": "#/definitions/publicIPAddressObjectType", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, "metadata": { - "description": "Required. The name of the virtual machine extension." + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, "metadata": { - "description": "Optional. The location the extension is deployed to." + "description": "Optional. The diagnostic settings of the service." } }, - "publisher": { - "type": "string", + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "description": "Required. The name of the extension handler publisher." + "description": "Optional. The lock settings of the service." } }, - "type": { + "skuName": { "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Developer", + "Premium", + "Standard" + ], "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + "description": "Optional. The SKU of this Bastion Host." } }, - "typeHandlerVersion": { - "type": "string", + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Specifies the version of the script handler." + "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." } }, - "autoUpgradeMinorVersion": { + "enableFileCopy": { "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." } }, - "forceUpdateTag": { - "type": "string", - "nullable": true, + "enableIpConnect": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." } }, - "settings": { - "type": "object", - "nullable": true, + "enableKerberos": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Any object that contains the extension specific settings." + "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." } }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." + "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." } }, - "supressFailures": { + "enableSessionRecording": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." } }, - "enableAutomaticUpgrade": { + "enablePrivateOnlyBastion": { "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." } }, - "tags": { - "type": "object", + "scaleUnits": { + "type": "int", + "defaultValue": 2, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_azureMonitorAgentExtension": { - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitor" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", "nullable": true, "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" }, "description": "Optional. Tags of the resource." }, "nullable": true }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + "description": "Optional. Enable/Disable usage telemetry for module." } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." + "availabilityZones": { + "type": "array", + "items": { + "type": "int" }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", + "defaultValue": [], + "allowedValues": [ + 1, + 2, + 3 + ], "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" + "description": "Optional. The list of Availability zones to use for the zone-redundant resources." + } } - } - } - }, - "dependsOn": [ - "vm", - "vm_microsoftAntiMalwareExtension" - ] - }, - "vm_dependencyAgentExtension": { - "condition": "[parameters('extensionDependencyAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitoring.DependencyAgent" }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" - }, - "settings": { - "value": { - "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[coalesce(parameters('tags'), createObject())]", + "sku": { + "name": "[parameters('skuName')]" }, - "nullable": true + "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", + "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + "azureBastion_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "nullable": true + "dependsOn": [ + "azureBastion" + ] }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + "azureBastion_diagnosticSettings": { + "copy": { + "name": "azureBastion_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "dependsOn": [ + "azureBastion" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "vm_networkWatcherAgentExtension": { - "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.NetworkWatcher" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } + "dependsOn": [ + "azureBastion" + ] }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_dependencyAgentExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "publicIPAddress": { + "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_networkWatcherAgentExtension" - ] - }, - "vm_customScriptExtension": { - "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" - }, - "provisionAfterExtensions": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettingsFromKeyVault": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" - }, - "settings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" - }, - "protectedSettings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "cseIdentity", - "vm" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_customScriptExtension" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - }, - "vm_hostPoolRegistrationExtension": { - "condition": "[parameters('extensionHostPoolRegistration').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.PowerShell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": { - "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", - "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", - "properties": { - "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", - "aadJoin": true - } - } - }, - "protectedSettings": { - "value": { - "properties": { - "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" - } - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_nvidiaGpuDriverWindowsExtension" - ] - }, - "vm_azureGuestConfigurationExtension": { - "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.GuestConfiguration" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" - }, - "protectedSettings": { - "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_hostPoolRegistrationExtension" - ] - }, - "vm_backup": { - "condition": "[not(empty(parameters('backupVaultName')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", - "resourceGroup": "[parameters('backupVaultResourceGroup')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "policyId": { - "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" - }, - "protectedItemType": { - "value": "Microsoft.Compute/virtualMachines" - }, - "protectionContainerName": { - "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" - }, - "recoveryVaultName": { - "value": "[parameters('backupVaultName')]" - }, - "sourceResourceId": { - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17448691641471706096" - }, - "name": "Recovery Service Vaults Protection Container Protected Item", - "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the resource." - } - }, - "protectionContainerName": { - "type": "string", - "metadata": { - "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." - } - }, - "recoveryVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "protectedItemType": { - "type": "string", - "allowedValues": [ - "AzureFileShareProtectedItem", - "AzureVmWorkloadSAPAseDatabase", - "AzureVmWorkloadSAPHanaDatabase", - "AzureVmWorkloadSQLDatabase", - "DPMProtectedItem", - "GenericProtectedItem", - "MabFileFolderProtectedItem", - "Microsoft.ClassicCompute/virtualMachines", - "Microsoft.Compute/virtualMachines", - "Microsoft.Sql/servers/databases" - ], - "metadata": { - "description": "Required. The backup item type." - } - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Required. ID of the backup policy with which this item is backed up." - } - }, - "sourceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource to back up." - } - } - }, - "resources": [ - { - "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", - "apiVersion": "2025-02-01", - "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "protectedItemType": "[parameters('protectedItemType')]", - "policyId": "[parameters('policyId')]", - "sourceResourceId": "[parameters('sourceResourceId')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the protected item was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the protected item." - }, - "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The Name of the protected item." - }, - "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2024-07-01', 'full').location]" - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationOutputType" - }, - "metadata": { - "description": "The list of NIC configurations of the virtual machine." - }, - "copy": { - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", - "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" - } - } - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "maintenanceConfiguration", - "virtualNetwork", - "windowsVmDataCollectionRules" - ] - }, - "maintenanceConfiguration": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('mc-{0}', variables('jumpboxVmName'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "extensionProperties": { - "value": { - "InGuestPatchMode": "User" - } - }, - "maintenanceScope": { - "value": "InGuestPatch" - }, - "maintenanceWindow": { - "value": { - "startDateTime": "2024-06-16 00:00", - "duration": "03:55", - "timeZone": "W. Europe Standard Time", - "recurEvery": "1Day" - } - }, - "visibility": { - "value": "Custom" - }, - "installPatches": { - "value": { - "rebootSetting": "IfRequired", - "windowsParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - }, - "linuxParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - } - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14895287194406877557" - }, - "name": "Maintenance Configurations", - "description": "This module deploys a Maintenance Configuration." - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Maintenance Configuration Name." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "extensionProperties": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" - }, - "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." - }, - "defaultValue": {} - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "maintenanceScope": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" - }, - "description": "Optional. Gets or sets maintenanceScope of the configuration." - }, - "defaultValue": "Host" - }, - "maintenanceWindow": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" - }, - "description": "Optional. Definition of a MaintenanceWindow." - }, - "defaultValue": {} - }, - "namespace": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Gets or sets namespace of the resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" - }, - "description": "Optional. Gets or sets tags of the resource." - }, - "nullable": true - }, - "visibility": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" - }, - "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." - }, - "nullable": true - }, - "installPatches": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" - }, - "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." - }, - "defaultValue": {} - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "maintenanceConfiguration": { - "type": "Microsoft.Maintenance/maintenanceConfigurations", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "extensionProperties": "[parameters('extensionProperties')]", - "maintenanceScope": "[parameters('maintenanceScope')]", - "maintenanceWindow": "[parameters('maintenanceWindow')]", - "namespace": "[parameters('namespace')]", - "visibility": "[parameters('visibility')]", - "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" - } - }, - "maintenanceConfiguration_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - }, - "maintenanceConfiguration_roleAssignments": { - "copy": { - "name": "maintenanceConfiguration_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Maintenance Configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Maintenance Configuration." - }, - "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Maintenance Configuration was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the Maintenance Configuration was created in." - }, - "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" - } - } - } - } - }, - "windowsVmDataCollectionRules": { - "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('dataCollectionRulesResourceName')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "location": { - "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" - }, - "dataCollectionRuleProperties": { - "value": { - "kind": "Windows", - "dataSources": { - "performanceCounters": [ - { - "streams": [ - "Microsoft-Perf" - ], - "samplingFrequencyInSeconds": 60, - "counterSpecifiers": [ - "\\Processor Information(_Total)\\% Processor Time", - "\\Processor Information(_Total)\\% Privileged Time", - "\\Processor Information(_Total)\\% User Time", - "\\Processor Information(_Total)\\Processor Frequency", - "\\System\\Processes", - "\\Process(_Total)\\Thread Count", - "\\Process(_Total)\\Handle Count", - "\\System\\System Up Time", - "\\System\\Context Switches/sec", - "\\System\\Processor Queue Length", - "\\Memory\\% Committed Bytes In Use", - "\\Memory\\Available Bytes", - "\\Memory\\Committed Bytes", - "\\Memory\\Cache Bytes", - "\\Memory\\Pool Paged Bytes", - "\\Memory\\Pool Nonpaged Bytes", - "\\Memory\\Pages/sec", - "\\Memory\\Page Faults/sec", - "\\Process(_Total)\\Working Set", - "\\Process(_Total)\\Working Set - Private", - "\\LogicalDisk(_Total)\\% Disk Time", - "\\LogicalDisk(_Total)\\% Disk Read Time", - "\\LogicalDisk(_Total)\\% Disk Write Time", - "\\LogicalDisk(_Total)\\% Idle Time", - "\\LogicalDisk(_Total)\\Disk Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Transfers/sec", - "\\LogicalDisk(_Total)\\Disk Reads/sec", - "\\LogicalDisk(_Total)\\Disk Writes/sec", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", - "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", - "\\LogicalDisk(_Total)\\% Free Space", - "\\LogicalDisk(_Total)\\Free Megabytes", - "\\Network Interface(*)\\Bytes Total/sec", - "\\Network Interface(*)\\Bytes Sent/sec", - "\\Network Interface(*)\\Bytes Received/sec", - "\\Network Interface(*)\\Packets/sec", - "\\Network Interface(*)\\Packets Sent/sec", - "\\Network Interface(*)\\Packets Received/sec", - "\\Network Interface(*)\\Packets Outbound Errors", - "\\Network Interface(*)\\Packets Received Errors" - ], - "name": "perfCounterDataSource60" - } - ], - "windowsEventLogs": [ - { - "name": "SecurityAuditEvents", - "streams": [ - "Microsoft-Event" - ], - "xPathQueries": [ - "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" - ] - } - ] - }, - "destinations": { - "logAnalytics": [ - { - "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", - "name": "[variables('dcrLogAnalyticsDestinationName')]" - } - ] - }, - "dataFlows": [ - { - "streams": [ - "Microsoft-Perf" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Perf" - }, - { - "streams": [ - "Microsoft-Event" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Event" - } - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2441324888126124697" - }, - "name": "Data Collection Rules", - "description": "This module deploys a Data Collection Rule." - }, - "definitions": { - "dataCollectionRulePropertiesType": { - "type": "object", - "discriminator": { - "propertyName": "kind", - "mapping": { - "Linux": { - "$ref": "#/definitions/linuxDcrPropertiesType" - }, - "Windows": { - "$ref": "#/definitions/windowsDcrPropertiesType" - }, - "All": { - "$ref": "#/definitions/allPlatformsDcrPropertiesType" - }, - "AgentSettings": { - "$ref": "#/definitions/agentSettingsDcrPropertiesType" - }, - "Direct": { - "$ref": "#/definitions/directDcrPropertiesType" - }, - "WorkspaceTransforms": { - "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" - }, - "PlatformTelemetry": { - "$ref": "#/definitions/platformTelemetryDcrPropertiesType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." - } - }, - "linuxDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Linux" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Linux' data collection rule." - } - }, - "windowsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Windows" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Windows' data collection rule." - } - }, - "allPlatformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "All" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the data collection rule of the kind 'All'." - } - }, - "agentSettingsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "AgentSettings" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "agentSettings": { - "$ref": "#/definitions/agentSettingsType", - "metadata": { - "description": "Required. Agent settings used to modify agent behavior on a given host." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'AgentSettings' data collection rule." - } - }, - "agentSettingsType": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "$ref": "#/definitions/agentSettingType" - }, - "metadata": { - "description": "Required. All the settings that are applicable to the logs agent (AMA)." - } - } - }, - "metadata": { - "description": "The type for the agent settings." - } - }, - "agentSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "MaxDiskQuotaInMB", - "UseTimeReceivedForForwardedEvents" - ], - "metadata": { - "description": "Required. The name of the agent setting." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. The value of the agent setting." - } - } - }, - "metadata": { - "description": "The type for the (single) agent setting." - } - }, - "directDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Direct" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Required. Declaration of custom streams used in this rule." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Direct' data collection rule." - } - }, - "workspaceTransformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "WorkspaceTransforms" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." - } - }, - "platformTelemetryDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "PlatformTelemetry" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "dataSources": { - "type": "object", - "properties": { - "platformTelemetry": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" - }, - "description": "Required. The list of platform telemetry configurations." - } - } - }, - "metadata": { - "description": "Required. Specification of data sources that will be collected." - } - }, - "destinations": { - "type": "object", - "properties": { - "logAnalytics": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" - }, - "description": "Optional. The list of Log Analytics destinations." - }, - "nullable": true - }, - "storageAccounts": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" - }, - "description": "Optional. The list of Storage Account destinations." - }, - "nullable": true - }, - "eventHubs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" - }, - "description": "Optional. The list of Event Hub destinations." - }, - "nullable": true - } - }, - "metadata": { - "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the data collection rule. The name is case insensitive." - } - }, - "dataCollectionRuleProperties": { - "$ref": "#/definitions/dataCollectionRulePropertiesType", - "metadata": { - "description": "Required. The kind of data collection rule." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "dataCollectionRule": { - "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "kind": "[parameters('dataCollectionRuleProperties').kind]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRuleAll": { - "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRule_conditionalScopeLock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", - "lock": { - "value": "[parameters('lock')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2876136109547890997" - } - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "dataCollectionRuleName": { - "type": "string", - "metadata": { - "description": "Required. Name of the Data Collection Rule to assign the role(s) to." - } - } - }, - "resources": { - "dataCollectionRule": { - "existing": true, - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('dataCollectionRuleName')]" - }, - "dataCollectionRule_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - } - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - }, - "dataCollectionRule_roleAssignments": { - "copy": { - "name": "dataCollectionRule_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", - "name": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "14634305923902101494" - }, - "name": "Resource-scoped role assignment", - "description": "This module deploys a Role Assignment for a specific resource." - }, - "parameters": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The scope for the role assignment, fully qualified resourceId." - } - }, - "name": { - "type": "string", - "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", - "metadata": { - "description": "Optional. The unique guid name for the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition ID for the role assignment." - } - }, - "roleName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The name for the role, used for logging." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of role assignment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string" - }, - "name": { - "type": "string" - }, - "roleDefinitionId": { - "type": "string" - }, - "principalId": { - "type": "string" - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string" - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "principalType": "[[parameters('principalType')]", - "description": "[[parameters('description')]" - } - } - ], - "outputs": { - "roleAssignmentId": { - "type": "string", - "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" - } - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", - "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "Outer" - }, - "template": "[variables('$fxv#0')]", - "parameters": { - "scope": { - "value": "[parameters('resourceId')]" - }, - "name": { - "value": "[parameters('name')]" - }, - "roleDefinitionId": { - "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" - }, - "principalId": { - "value": "[parameters('principalId')]" - }, - "principalType": { - "value": "[parameters('principalType')]" - }, - "description": { - "value": "[parameters('description')]" - } - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[parameters('name')]" - }, - "roleName": { - "type": "string", - "metadata": { - "description": "The name for the role, used for logging." - }, - "value": "[parameters('roleName')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the dataCollectionRule was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" - }, - "endpoints": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", - "output": true - }, - "description": "The endpoints of the dataCollectionRule, if created." - }, - "nullable": true, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" - }, - "immutableId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The ImmutableId of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmPrivateDnsZones": { - "copy": { - "name": "avmPrivateDnsZones", - "count": "[length(variables('privateDnsZones'))]", - "mode": "serial", - "batchSize": 5 - }, - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZones')[copyIndex()]]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "virtualNetworkLinks": { - "value": [ - { - "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18337341331267624582" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone." - }, - "definitions": { - "aType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" - }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the A record." - } - }, - "aaaaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the AAAA record." - } - }, - "cnameType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. The CNAME record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the CNAME record." - } - }, - "mxType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the MX record." - } - }, - "ptrType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the PTR record." - } - }, - "soaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "soaRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" - }, - "description": "Optional. The SOA record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SOA record." - } - }, - "srvType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "srvRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" - }, - "description": "Optional. The list of SRV records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SRV record." - } - }, - "txtType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "txtRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" - }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the TXT record." - } - }, - "virtualNetworkLinkType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 1, - "maxLength": 80, - "metadata": { - "description": "Optional. The resource name." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the virtual network to link." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Region where the resource lives." - } - }, - "registrationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - }, - "resolutionPolicy": { - "type": "string", - "allowedValues": [ - "Default", - "NxDomainRedirect" - ], - "nullable": true, - "metadata": { - "description": "Optional. The resolution type of the private-dns-zone fallback machanism." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network link." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "a": { - "type": "array", - "items": { - "$ref": "#/definitions/aType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of A records." - } - }, - "aaaa": { - "type": "array", - "items": { - "$ref": "#/definitions/aaaaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of AAAA records." - } - }, - "cname": { - "type": "array", - "items": { - "$ref": "#/definitions/cnameType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of CNAME records." - } - }, - "mx": { - "type": "array", - "items": { - "$ref": "#/definitions/mxType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of MX records." - } - }, - "ptr": { - "type": "array", - "items": { - "$ref": "#/definitions/ptrType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of PTR records." - } - }, - "soa": { - "type": "array", - "items": { - "$ref": "#/definitions/soaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SOA records." - } - }, - "srv": { - "type": "array", - "items": { - "$ref": "#/definitions/srvType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SRV records." - } - }, - "txt": { - "type": "array", - "items": { - "$ref": "#/definitions/txtType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of TXT records." - } - }, - "virtualNetworkLinks": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkLinkType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_roleAssignments": { - "copy": { - "name": "privateDnsZone_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_A": { - "copy": { - "name": "privateDnsZone_A", - "count": "[length(coalesce(parameters('a'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" - }, - "aRecords": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7372385900111002873" - }, - "name": "Private DNS Zone A record", - "description": "This module deploys a Private DNS Zone A record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the A record." - } - }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" - }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "A": { - "type": "Microsoft.Network/privateDnsZones/A", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aRecords": "[parameters('aRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "A_roleAssignments": { - "copy": { - "name": "A_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "A" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed A record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed A record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed A record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_AAAA": { - "copy": { - "name": "privateDnsZone_AAAA", - "count": "[length(coalesce(parameters('aaaa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" - }, - "aaaaRecords": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14405855828972373002" - }, - "name": "Private DNS Zone AAAA record", - "description": "This module deploys a Private DNS Zone AAAA record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the AAAA record." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "AAAA": { - "type": "Microsoft.Network/privateDnsZones/AAAA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aaaaRecords": "[parameters('aaaaRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "AAAA_roleAssignments": { - "copy": { - "name": "AAAA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "AAAA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AAAA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed AAAA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed AAAA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_CNAME": { - "copy": { - "name": "privateDnsZone_CNAME", - "count": "[length(coalesce(parameters('cname'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" - }, - "cnameRecord": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13818627461335065928" - }, - "name": "Private DNS Zone CNAME record", - "description": "This module deploys a Private DNS Zone CNAME record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the CNAME record." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. A CNAME record." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "CNAME": { - "type": "Microsoft.Network/privateDnsZones/CNAME", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "cnameRecord": "[parameters('cnameRecord')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "CNAME_roleAssignments": { - "copy": { - "name": "CNAME_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "CNAME" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed CNAME record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed CNAME record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed CNAME record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_MX": { - "copy": { - "name": "privateDnsZone_MX", - "count": "[length(coalesce(parameters('mx'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" - }, - "mxRecords": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2977624679479439942" - }, - "name": "Private DNS Zone MX record", - "description": "This module deploys a Private DNS Zone MX record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the MX record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "MX": { - "type": "Microsoft.Network/privateDnsZones/MX", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "mxRecords": "[parameters('mxRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "MX_roleAssignments": { - "copy": { - "name": "MX_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "MX" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed MX record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed MX record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed MX record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_PTR": { - "copy": { - "name": "privateDnsZone_PTR", - "count": "[length(coalesce(parameters('ptr'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" - }, - "ptrRecords": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "15286275176817336979" - }, - "name": "Private DNS Zone PTR record", - "description": "This module deploys a Private DNS Zone PTR record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the PTR record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "PTR": { - "type": "Microsoft.Network/privateDnsZones/PTR", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ptrRecords": "[parameters('ptrRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "PTR_roleAssignments": { - "copy": { - "name": "PTR_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "PTR" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed PTR record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed PTR record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed PTR record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SOA": { - "copy": { - "name": "privateDnsZone_SOA", - "count": "[length(coalesce(parameters('soa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" - }, - "soaRecord": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4837447718856535826" - }, - "name": "Private DNS Zone SOA record", - "description": "This module deploys a Private DNS Zone SOA record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SOA record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "soaRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" - }, - "description": "Optional. A SOA record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SOA": { - "type": "Microsoft.Network/privateDnsZones/SOA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "soaRecord": "[parameters('soaRecord')]", - "ttl": "[parameters('ttl')]" - } - }, - "SOA_roleAssignments": { - "copy": { - "name": "SOA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "SOA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SOA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SOA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SOA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SRV": { - "copy": { - "name": "privateDnsZone_SRV", - "count": "[length(coalesce(parameters('srv'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" - }, - "srvRecords": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "15028912535488490265" - }, - "name": "Private DNS Zone SRV record", - "description": "This module deploys a Private DNS Zone SRV record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SRV record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "srvRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" - }, - "description": "Optional. The list of SRV records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SRV": { - "type": "Microsoft.Network/privateDnsZones/SRV", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "srvRecords": "[parameters('srvRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "SRV_roleAssignments": { - "copy": { - "name": "SRV_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "SRV" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SRV record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SRV record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SRV record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_TXT": { - "copy": { - "name": "privateDnsZone_TXT", - "count": "[length(coalesce(parameters('txt'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" - }, - "txtRecords": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7641583415110009849" - }, - "name": "Private DNS Zone TXT record", - "description": "This module deploys a Private DNS Zone TXT record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the TXT record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "txtRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" - }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "TXT": { - "type": "Microsoft.Network/privateDnsZones/TXT", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]", - "txtRecords": "[parameters('txtRecords')]" - } - }, - "TXT_roleAssignments": { - "copy": { - "name": "TXT_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "TXT" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed TXT record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed TXT record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed TXT record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "resolutionPolicy": { - "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7392770862892927923" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link." - }, - "parameters": { - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - }, - "resolutionPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - }, - "resolutionPolicy": "[parameters('resolutionPolicy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "logAnalyticsWorkspace": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "name": { - "value": "[variables('logAnalyticsWorkspaceResourceName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableReplication": { - "value": "[parameters('enableRedundancy')]" - }, - "replicationLocation": { - "value": "[variables('replicaLocation')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "9919485194443011422" - } - }, - "parameters": { - "solutionName": { - "type": "string", - "metadata": { - "description": "Solution name suffix used to derive the resource name." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('log-{0}', parameters('solutionName'))]", - "metadata": { - "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region for the resource." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resource." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": 365, - "metadata": { - "description": "Retention period in days. WAF recommends 365." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "metadata": { - "description": "SKU name for the workspace." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Public network access for ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Public network access for query." - } - }, - "enableReplication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable workspace replication for redundancy." - } - }, - "replicationLocation": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Replication location (paired region)." - } - }, - "dailyQuotaGb": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." - } - }, - "dataSources": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Data sources for VM monitoring (Windows events, perf counters)." - } - } - }, - "resources": { - "workspace": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "dataRetention": { - "value": "[parameters('retentionInDays')]" - }, - "skuName": { - "value": "[parameters('skuName')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "features": { - "value": { - "enableLogAccessUsingOnlyResourcePermissions": true - } - }, - "diagnosticSettings": { - "value": [ - { - "useThisWorkspace": true - } - ] - }, - "publicNetworkAccessForIngestion": { - "value": "[parameters('publicNetworkAccessForIngestion')]" - }, - "publicNetworkAccessForQuery": { - "value": "[parameters('publicNetworkAccessForQuery')]" - }, - "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", - "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", - "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14099489006827800075" - }, - "name": "Log Analytics Workspaces", - "description": "This module deploys a Log Analytics Workspace." - }, - "definitions": { - "diagnosticSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "useThisWorkspace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "gallerySolutionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the gallery solutions to be created in the log analytics workspace." - } - }, - "storageInsightsConfigType": { - "type": "object", - "properties": { - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the storage account to be linked." - } - }, - "containers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of tables to be read by the workspace." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the storage insights configuration." - } - }, - "linkedServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." - } - }, - "writeAccessResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked service." - } - }, - "linkedStorageAccountType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the link." - } - }, - "storageAccountIds": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked storage account." - } - }, - "savedSearchType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "etag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. The category of the saved search. This helps the user to find a saved search faster." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "functionAlias": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The function alias if query serves as a function." - } - }, - "functionParameters": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. The query expression for the saved search." - } - }, - "tags": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The tags attached to the saved search." - } - }, - "version": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The version number of the query language. The current version is 2 and is the default." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the saved search." - } - }, - "dataExportType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data export." - } - }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, - "metadata": { - "description": "Optional. The destination of the data export." - } - }, - "enable": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the data export." - } - }, - "tableNames": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of table names to export." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the data export." - } - }, - "dataSourceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "metadata": { - "description": "Required. The kind of data source." - } - }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the event log to configure when kind is WindowsEvent." - } - }, - "eventTypes": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "intervalSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." - } - }, - "syslogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." - } - }, - "syslogSeverities": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the data source." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "plan": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The plan for the table." - } - }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, - "metadata": { - "description": "Optional. The restored logs for the table." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. The schema for the table." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, - "metadata": { - "description": "Optional. The search results for the table." - } - }, - "retentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, - "metadata": { - "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." - } - }, - "totalRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 2555, - "metadata": { - "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The role assignments for the table." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the custom table." - } - }, - "workspaceFeaturesType": { - "type": "object", - "properties": { - "disableLocalAuth": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Disable Non-EntraID based Auth. Default is true." - } - }, - "enableDataExport": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag that indicate if data should be exported." - } - }, - "enableLogAccessUsingOnlyResourcePermissions": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable log access using only resource permissions. Default is false." - } - }, - "immediatePurgeDataOn30Days": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag that describes if we want to remove the data after 30 days." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Features of the workspace." - } - }, - "workspaceReplicationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Replication properties of the workspace." - } - }, - "_1.columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], - "metadata": { - "description": "Required. The column type." - } - }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], - "nullable": true, - "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Column display name." - } - } - }, - "metadata": { - "description": "The parameters of the table column.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "destinationType": { - "type": "object", - "properties": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The destination resource ID." - } - }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination metadata." - } - } - }, - "metadata": { - "description": "The data export destination properties.", - "__bicep_imported_from!": { - "sourceTemplate": "data-export/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "restoredLogsType": { - "type": "object", - "properties": { - "sourceTable": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table to restore data from." - } - }, - "startRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." - } - }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the restore operation that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "description": "The table schema.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the search job that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Log Analytics workspace." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "allowedValues": [ - "CapacityReservation", - "Free", - "LACluster", - "PerGB2018", - "PerNode", - "Premium", - "Standalone", - "Standard" - ], - "metadata": { - "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." - } - }, - "skuCapacityReservationLevel": { - "type": "int", - "defaultValue": 100, - "minValue": 100, - "maxValue": 5000, - "metadata": { - "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." - } - }, - "storageInsightsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/storageInsightsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of storage accounts to be read by the workspace." - } - }, - "linkedServices": { - "type": "array", - "items": { - "$ref": "#/definitions/linkedServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of services to be linked." - } - }, - "linkedStorageAccounts": { - "type": "array", - "items": { - "$ref": "#/definitions/linkedStorageAccountType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." - } - }, - "savedSearches": { - "type": "array", - "items": { - "$ref": "#/definitions/savedSearchType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Kusto Query Language searches to save." - } - }, - "dataExports": { - "type": "array", - "items": { - "$ref": "#/definitions/dataExportType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW data export instances to be deployed." - } - }, - "dataSources": { - "type": "array", - "items": { - "$ref": "#/definitions/dataSourceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW data sources to configure." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW custom tables to be deployed." - } - }, - "gallerySolutions": { - "type": "array", - "items": { - "$ref": "#/definitions/gallerySolutionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." - } - }, - "onboardWorkspaceToSentinel": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." - } - }, - "dataRetention": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 730, - "metadata": { - "description": "Optional. Number of days data will be retained for." - } - }, - "dailyQuotaGb": { - "type": "string", - "defaultValue": "-1", - "metadata": { - "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." - } - }, - "defaultDataCollectionRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics query." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." - } - }, - "features": { - "$ref": "#/definitions/workspaceFeaturesType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace features." - } - }, - "replication": { - "$ref": "#/definitions/workspaceReplicationType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace replication properties." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "forceCmkForQuery": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether customer managed storage is mandatory for query management." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", - "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "features": { - "searchVersion": 1, - "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", - "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", - "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", - "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" - }, - "retentionInDays": "[parameters('dataRetention')]", - "workspaceCapping": { - "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" - }, - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "forceCmkForQuery": "[parameters('forceCmkForQuery')]", - "replication": "[parameters('replication')]", - "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" - }, - "identity": "[variables('identity')]" - }, - "logAnalyticsWorkspace_diagnosticSettings": { - "copy": { - "name": "logAnalyticsWorkspace_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_sentinelOnboarding": { - "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", - "type": "Microsoft.SecurityInsights/onboardingStates", - "apiVersion": "2025-09-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "default", - "properties": {}, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_roleAssignments": { - "copy": { - "name": "logAnalyticsWorkspace_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_storageInsightConfigs": { - "copy": { - "name": "logAnalyticsWorkspace_storageInsightConfigs", - "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "containers": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" - }, - "tables": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" - } + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" + }, + "ipTags": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -20746,4043 +9860,10326 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "140290971998938797" + "templateHash": "16564959277054027786" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "Log Analytics Workspace Storage Insight Configs", - "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { - "logAnalyticsWorkspaceName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "Required. The name of the Public IP Address." } }, - "name": { + "publicIpPrefixResourceId": { "type": "string", - "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "nullable": true, "metadata": { - "description": "Optional. The name of the storage insights config." + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." } }, - "storageAccountResourceId": { + "publicIPAllocationMethod": { "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], "metadata": { - "description": "Required. The Azure Resource Manager ID of the storage account resource." + "description": "Optional. The public IP address allocation method." } }, - "containers": { + "availabilityZones": { "type": "array", "items": { - "type": "string" + "type": "int" }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", "nullable": true, "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." + "description": "Optional. The DNS settings of the public IP address." } }, - "tables": { + "ipTags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/ipTagType" }, "nullable": true, "metadata": { - "description": "Optional. The names of the Azure tables that the workspace should read." + "description": "Optional. The list of tags associated with the public IP address." } }, - "tags": { - "type": "object", + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" - }, - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "storageinsightconfig": { - "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "containers": "[parameters('containers')]", - "tables": "[parameters('tables')]", - "storageAccount": { - "id": "[parameters('storageAccountResourceId')]", - "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - } + "description": "Optional. The lock settings of the service." } - } - }, - "outputs": { - "resourceId": { + }, + "skuName": { "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], "metadata": { - "description": "The resource ID of the deployed storage insights configuration." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "description": "Optional. Name of a public IP address SKU." + } }, - "resourceGroupName": { + "skuTier": { "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], "metadata": { - "description": "The resource group where the storage insight configuration is deployed." - }, - "value": "[resourceGroup().name]" + "description": "Optional. Tier of a public IP address SKU." + } }, - "name": { - "type": "string", + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, "metadata": { - "description": "The name of the storage insights configuration." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_linkedServices": { - "copy": { - "name": "logAnalyticsWorkspace_linkedServices", - "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" - }, - "resourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" - }, - "writeAccessResourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14482465616812596213" + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } }, - "name": "Log Analytics Workspace Linked Services", - "description": "This module deploys a Log Analytics Workspace Linked Service." - }, - "parameters": { - "logAnalyticsWorkspaceName": { + "deleteOption": { "type": "string", + "nullable": true, + "allowedValues": [ + "Delete", + "Detach" + ], "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + "description": "Optional. The delete option for the public IP address." } }, - "name": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Name of the link." + "description": "Optional. Location for all resources." } }, - "resourceId": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + "description": "Optional. Array of role assignments to create." } }, - "writeAccessResourceId": { - "type": "string", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" }, - "description": "Optional. Tags to configure in the resource." + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "nullable": true - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "dependsOn": [ + "publicIpAddress" + ] }, - "linkedService": { - "type": "Microsoft.OperationalInsights/workspaces/linkedServices", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { - "resourceId": "[parameters('resourceId')]", - "writeAccessResourceId": "[parameters('writeAccessResourceId')]" - } + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] } }, "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the deployed linked service." + "description": "The name of the public IP address." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed linked service." + "description": "The resource ID of the public IP address." }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" }, - "resourceGroupName": { + "ipAddress": { "type": "string", "metadata": { - "description": "The resource group where the linked service is deployed." + "description": "The public IP address of the public IP address resource." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" } } } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure Bastion was deployed into." }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "value": "[resourceGroup().name]" }, - "logAnalyticsWorkspace_linkedStorageAccounts": { - "copy": { - "name": "logAnalyticsWorkspace_linkedStorageAccounts", - "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" + "name": { + "type": "string", + "metadata": { + "description": "The name the Azure Bastion." }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID the Azure Bastion." + }, + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureBastion', '2025-01-01', 'full').location]" + }, + "ipConfAzureBastionSubnet": { + "type": "object", + "metadata": { + "description": "The Public IPconfiguration object for the AzureBastionSubnet." + }, + "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Bastion host." + }, + "value": "[reference('bastionHost').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the Bastion host." + }, + "value": "[reference('bastionHost').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.virtual-machine.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('jumpboxVmName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "computerName": { + "value": "[take(variables('jumpboxVmName'), 15)]" + }, + "osType": { + "value": "Windows" + }, + "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", + "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", + "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": true + }, + "maintenanceConfigurationResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.maintenance-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", + "imageReference": { + "value": { + "publisher": "microsoft-dsvm", + "offer": "dsvm-win-2022", + "sku": "winserver-2022", + "version": "latest" + } + }, + "osDisk": { + "value": { + "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" + } + } + }, + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-{0}', variables('jumpboxVmName'))]", + "tags": "[parameters('tags')]", + "deleteOption": "Delete", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value)), null())]", + "ipConfigurations": [ + { + "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", + "subnetResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.administrationSubnetResourceId.value]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value)), null())]" + } + ] + } + ] + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]", + "typeHandlerVersion": "1.0", + "settings": { + "mdmId": "" + } + } + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": {}, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + }, + "tags": "[parameters('tags')]" + } + }, + "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.data-collection-rule.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value, 'name', format('send-{0}', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17290221824154908545" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the virtual machine." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "computerName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Computer name of the virtual machine." + } + }, + "osType": { + "type": "string", + "metadata": { + "description": "Operating system type." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Virtual machine size." + } + }, + "adminUsername": { + "type": "string", + "metadata": { + "description": "Administrator username for the virtual machine." + } + }, + "adminPassword": { + "type": "securestring", + "metadata": { + "description": "Administrator password for the virtual machine." + } + }, + "managedIdentities": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Patch mode for the virtual machine." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether platform safety checks should be bypassed for user schedules." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Maintenance configuration resource ID." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether automatic updates are enabled." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to enable encryption at host." + } + }, + "availabilityZone": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Availability zone for the virtual machine." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "description": "Image reference used to create the virtual machine." + } + }, + "osDisk": { + "type": "object", + "metadata": { + "description": "OS disk configuration for the virtual machine." + } + }, + "nicConfigurations": { + "type": "array", + "metadata": { + "description": "Network interface configurations for the virtual machine." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Azure AD join extension configuration." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Anti-malware extension configuration." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Monitoring agent extension configuration." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Network watcher extension configuration." + } + } + }, + "resources": { + "virtualMachine": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.compute.virtual-machine.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "computerName": "[if(not(empty(parameters('computerName'))), createObject('value', parameters('computerName')), createObject('value', null()))]", + "osType": { + "value": "[parameters('osType')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "adminUsername": { + "value": "[parameters('adminUsername')]" + }, + "adminPassword": { + "value": "[parameters('adminPassword')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "patchMode": "[if(not(empty(parameters('patchMode'))), createObject('value', parameters('patchMode')), createObject('value', null()))]", + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": "[parameters('bypassPlatformSafetyChecksOnUserSchedule')]" + }, + "maintenanceConfigurationResourceId": "[if(not(empty(parameters('maintenanceConfigurationResourceId'))), createObject('value', parameters('maintenanceConfigurationResourceId')), createObject('value', null()))]", + "enableAutomaticUpdates": { + "value": "[parameters('enableAutomaticUpdates')]" + }, + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" + }, + "availabilityZone": { + "value": "[parameters('availabilityZone')]" + }, + "imageReference": { + "value": "[parameters('imageReference')]" + }, + "osDisk": { + "value": "[parameters('osDisk')]" + }, + "nicConfigurations": { + "value": "[parameters('nicConfigurations')]" + }, + "extensionAadJoinConfig": { + "value": "[parameters('extensionAadJoinConfig')]" + }, + "extensionAntiMalwareConfig": { + "value": "[parameters('extensionAntiMalwareConfig')]" + }, + "extensionMonitoringAgentConfig": { + "value": "[parameters('extensionMonitoringAgentConfig')]" + }, + "extensionNetworkWatcherAgentConfig": { + "value": "[parameters('extensionNetworkWatcherAgentConfig')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17174537341033050778" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." + }, + "definitions": { + "osDiskType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" - }, - "storageAccountIds": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14864721709229272590" - }, - "name": "Log Analytics Workspace Linked Storage Accounts", - "description": "This module deploys a Log Analytics Workspace Linked Storage Account." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { + "description": "Optional. Specifies the caching requirements." + } + }, + "diffDiskSettings": { + "type": "object", + "properties": { + "placement": { "type": "string", "allowedValues": [ - "Query", - "Alerts", - "CustomLogs", - "AzureWatson" + "CacheDisk", + "NvmeDisk", + "ResourceDisk" ], "metadata": { - "description": "Required. Name of the link." - } - }, - "storageAccountIds": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "linkedStorageAccount": { - "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "properties": { - "storageAccountIds": "[parameters('storageAccountIds')]" + "description": "Required. Specifies the ephemeral disk placement for the operating system disk." } } }, - "outputs": { - "name": { + "nullable": true, + "metadata": { + "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, "metadata": { - "description": "The name of the deployed linked storage account." - }, - "value": "[parameters('name')]" + "description": "Optional. Specifies the storage account type for the managed disk." + } }, - "resourceId": { + "diskEncryptionSetResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource ID of the deployed linked storage account." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } }, - "resourceGroupName": { + "resourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group where the linked storage account is deployed." - }, - "value": "[resourceGroup().name]" + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } } + }, + "metadata": { + "description": "Required. The managed disk parameters." } } }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type describing an OS disk." + } }, - "logAnalyticsWorkspace_savedSearches": { - "copy": { - "name": "logAnalyticsWorkspace_savedSearches", - "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "dataDiskType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." + } }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" - }, - "etag": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" - }, - "displayName": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" - }, - "category": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" - }, - "query": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" - }, - "functionAlias": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" - }, - "functionParameters": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" - }, - "tags": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" - }, - "version": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "diskSizeGB": { + "type": "int", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17904092372918022238" - }, - "name": "Log Analytics Workspace Saved Searches", - "description": "This module deploys a Log Analytics Workspace Saved Search." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. Query category." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. Kusto Query to be stored." - } - }, - "tags": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - }, - "functionAlias": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { "type": "string", - "defaultValue": "", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, "metadata": { - "description": "Optional. The function alias if query serves as a function." + "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." } }, - "functionParameters": { + "diskEncryptionSetResourceId": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "version": { - "type": "int", "nullable": true, "metadata": { - "description": "Optional. The version number of the query language." + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." } }, - "etag": { + "resourceId": { "type": "string", - "defaultValue": "*", + "nullable": true, "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." } } }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" + "metadata": { + "description": "Required. The managed disk parameters." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" }, - "savedSearch": { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "properties": { - "etag": "[parameters('etag')]", - "tags": "[coalesce(parameters('tags'), createArray())]", - "displayName": "[parameters('displayName')]", - "category": "[parameters('category')]", - "query": "[parameters('query')]", - "functionAlias": "[parameters('functionAlias')]", - "functionParameters": "[parameters('functionParameters')]", - "version": "[parameters('version')]" - } - } + "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." }, - "outputs": { - "resourceId": { + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a data disk." + } + }, + "publicKeyType": { + "type": "object", + "properties": { + "keyData": { + "type": "string", + "metadata": { + "description": "Required. Specifies the SSH public key data used to authenticate through ssh." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." + } + } + } + }, + "nicConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the NIC configuration." + } + }, + "nicSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The suffix to append to the NIC name." + } + }, + "enableIPForwarding": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify what happens to the network interface when the VM is deleted." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "metadata": { + "description": "Required. The IP configurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the NIC configuration." + } + }, + "imageReferenceType": { + "type": "object", + "properties": { + "communityGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." + } + }, + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource Id of the image reference." + } + }, + "offer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The image publisher." + } + }, + "sku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SKU of the image." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." + } + }, + "sharedGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the image reference." + } + }, + "planType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the plan." + } + }, + "product": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the product of the image from the marketplace." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher ID." + } + }, + "promotionCode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The promotion code." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Specifies information about the marketplace image used to create the virtual machine." + } + }, + "autoShutDownConfigType": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the auto shutdown configuration." + } + }, + "timeZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." + } + }, + "dailyRecurrenceTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time of day the schedule will occur." + } + }, + "notificationSettings": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the notification settings." + } + }, + "emailRecipient": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource ID of the deployed saved search." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." + } }, - "resourceGroupName": { + "notificationLocale": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group where the saved search is deployed." - }, - "value": "[resourceGroup().name]" + "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + } }, - "name": { + "webhookUrl": { "type": "string", + "nullable": true, "metadata": { - "description": "The name of the deployed saved search." + "description": "Optional. The webhook URL to which the notification will be sent." + } + }, + "timeInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The time in minutes before shutdown to send notifications." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the schedule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the configuration profile." + } + }, + "vaultSecretGroupType": { + "type": "object", + "properties": { + "sourceVault": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." + } + }, + "vaultCertificates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "certificateStore": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + } }, - "value": "[parameters('name')]" + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." + } + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of key vault references in SourceVault which contain certificates." } } }, - "dependsOn": [ - "logAnalyticsWorkspace", - "logAnalyticsWorkspace_linkedStorageAccounts" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type describing the set of certificates that should be installed onto the virtual machine." + } }, - "logAnalyticsWorkspace_dataExports": { - "copy": { - "name": "logAnalyticsWorkspace_dataExports", - "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + "vmGalleryApplicationType": { + "type": "object", + "properties": { + "packageReferenceId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." + } + }, + "configurationReference": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." + } + }, + "order": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the order in which the packages have to be installed." + } + }, + "tags": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies a passthrough value for more generic context." + } + }, + "treatFailureAsDeploymentFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." + } + } }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "metadata": { + "__bicep_export!": true, + "description": "The type describing the gallery application that should be made available to the VM/VMSS." + } + }, + "additionalUnattendContentType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "settingName": { + "type": "string", + "allowedValues": [ + "AutoLogon", + "FirstLogonCommands" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the setting to which the content applies." + } }, - "mode": "Incremental", - "parameters": { - "workspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" - }, - "destination": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" - }, - "enable": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + "content": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." + } + }, + "winRMListenerType": { + "type": "object", + "properties": { + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Http", + "Https" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the protocol of WinRM listener." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a Windows Remote Management listener." + } + }, + "nicConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NIC configuration." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" }, - "tableNames": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + "metadata": { + "description": "Required. List of IP configurations of the NIC configuration." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the network interface configuration output." + } + }, + "extensionCustomScriptConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "typeHandlerVersion": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17943947755417749524" + "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + } }, - "name": "Log Analytics Workspace Data Exports", - "description": "This module deploys a Log Analytics Workspace Data Export." - }, - "definitions": { - "destinationType": { - "type": "object", - "properties": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The destination resource ID." - } - }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination metadata." - } - } + "fileUris": { + "type": "array", + "items": { + "type": "string" }, + "nullable": true, "metadata": { - "__bicep_export!": true, - "description": "The data export destination properties." + "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." } } }, - "parameters": { - "name": { + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "protectedSettings": { + "type": "secureObject", + "properties": { + "commandToExecute": { "type": "string", - "minLength": 4, - "maxLength": 63, + "nullable": true, "metadata": { - "description": "Required. The data export rule name." + "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." } }, - "workspaceName": { + "storageAccountName": { "type": "string", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." } }, - "destination": { - "$ref": "#/definitions/destinationType", + "storageAccountKey": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Destination properties." + "description": "Optional. The access key of the storage account." } }, - "enable": { - "type": "bool", - "defaultValue": false, + "managedIdentityResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Active when enabled." + "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." } }, - "tableNames": { + "fileUris": { "type": "array", "items": { "type": "string" }, - "minLength": 1, + "nullable": true, "metadata": { - "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + "description": "Optional. URLs for files to be downloaded." } } }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "supressFailures": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" }, - "dataExport": { - "type": "Microsoft.OperationalInsights/workspaces/dataExports", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", - "properties": { - "destination": "[parameters('destination')]", - "enable": "[parameters('enable')]", - "tableNames": "[parameters('tableNames')]" - } - } + "description": "Optional. Tags of the resource." }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the data export." - }, - "value": "[parameters('name')]" + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the data export." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the data export was created in." + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a 'CustomScriptExtension' extension." + } + }, + "_1.applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } }, - "value": "[resourceGroup().name]" + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." } } }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "logAnalyticsWorkspace_dataSources": { - "copy": { - "name": "logAnalyticsWorkspace_dataSources", - "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + "_1.applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.backendAddressPoolType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" - }, - "kind": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" - }, - "linkedResourceId": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" - }, - "eventLogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" - }, - "eventTypes": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" - }, - "objectName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" - }, - "instanceName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" - }, - "intervalSeconds": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" - }, - "counterName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" - }, - "state": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" - }, - "syslogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" - }, - "syslogSeverities": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" - }, - "performanceCounters": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" - }, - "tags": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "name": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "15360290236166491819" - }, - "name": "Log Analytics Workspace Datasources", - "description": "This module deploys a Log Analytics Workspace Data Source." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "defaultValue": "AzureActivityLog", - "allowedValues": [ - "AzureActivityLog", - "WindowsEvent", - "WindowsPerformanceCounter", - "IISLogs", - "LinuxSyslog", - "LinuxSyslogCollection", - "LinuxPerformanceObject", - "LinuxPerformanceCollection" - ], - "metadata": { - "description": "Optional. The kind of the data source." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - }, - "linkedResourceId": { - "type": "string", + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/_1.subResourceType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the resource to be linked." + "description": "Optional. A reference to backendAddressPool resource." } }, - "eventLogName": { - "type": "string", + "backendPort": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." } }, - "eventTypes": { - "type": "array", - "defaultValue": [], + "enableFloatingIP": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. Windows event types to configure when kind is WindowsEvent." + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." } }, - "objectName": { - "type": "string", + "enableTcpReset": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." } }, - "instanceName": { - "type": "string", - "defaultValue": "*", + "frontendIPConfiguration": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + "description": "Optional. A reference to frontend IP addresses." } }, - "intervalSeconds": { + "frontendPort": { "type": "int", - "defaultValue": 60, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." } }, - "counterName": { - "type": "string", + "frontendPortRangeStart": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." } }, - "state": { - "type": "string", + "frontendPortRangeEnd": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." } }, - "syslogName": { + "protocol": { "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], "nullable": true, "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." - } - }, - "syslogSeverities": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." + "description": "Optional. The reference to the transport protocol used by the load balancing rule." } } }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "dataSource": { - "type": "Microsoft.OperationalInsights/workspaces/dataSources", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "kind": "[parameters('kind')]", - "tags": "[parameters('tags')]", - "properties": { - "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", - "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", - "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", - "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", - "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", - "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", - "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", - "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", - "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", - "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", - "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_2.ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." } } }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed data source." + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_2.dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_2.ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "_3.diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the data source is deployed." + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed data source." + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } }, - "value": "[parameters('name')]" + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_3.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "logAnalyticsWorkspace_tables": { - "copy": { - "name": "logAnalyticsWorkspace_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "_4.publicIPConfigurationType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } }, - "mode": "Incremental", - "parameters": { - "workspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "plan": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" - }, - "schema": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" - }, - "retentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" - }, - "totalRetentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" - }, - "restoredLogs": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" }, - "searchResults": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/_3.lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/_2.ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/_2.dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.roleAssignmentType" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "18383178824663161801" + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" }, - "name": "Log Analytics Workspace Tables", - "description": "This module deploys a Log Analytics Workspace Table." + "description": "Optional. The tags of the public IP address." }, - "definitions": { - "restoredLogsType": { - "type": "object", - "properties": { - "sourceTable": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table to restore data from." - } - }, - "startRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." - } - }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the restore operation that initiated the table." - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The table schema." - } - }, - "columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], - "metadata": { - "description": "Required. The column type." - } - }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], - "nullable": true, - "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Column display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the table column." - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the search job that initiated the table." - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "description": "The type for the public IP address configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." } }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } } }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." - } - }, - "plan": { - "type": "string", - "defaultValue": "Analytics", - "allowedValues": [ - "Basic", - "Analytics" - ], - "metadata": { - "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." - } - }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, - "metadata": { - "description": "Optional. Restore parameters." - } - }, - "retentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, - "metadata": { - "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. Table's schema." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, - "metadata": { - "description": "Optional. Parameters of the search job that initiated this table." - } - }, - "totalRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 2555, - "metadata": { - "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.backendAddressPoolType" }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" - }, - "table": { - "type": "Microsoft.OperationalInsights/workspaces/tables", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", - "properties": { - "plan": "[parameters('plan')]", - "restoredLogs": "[parameters('restoredLogs')]", - "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", - "schema": "[parameters('schema')]", - "searchResults": "[parameters('searchResults')]", - "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" - } - }, - "table_roleAssignments": { - "copy": { - "name": "table_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "table" - ] - } + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationSecurityGroupType" }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/_4.publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "description": "The type for the IP configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "description": "The type for the network interface IP configuration output.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "logAnalyticsWorkspace_solutions": { - "copy": { - "name": "logAnalyticsWorkspace_solutions", - "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" - }, - "condition": "[not(empty(parameters('gallerySolutions')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "subResourceType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "plan": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "id": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "10255889523646649592" - }, - "name": "Operations Management Solutions", - "description": "This module deploys an Operations Management Solution.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - }, - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2021-06-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "solution": { - "type": "Microsoft.OperationsManagement/solutions", - "apiVersion": "2015-11-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" - }, - "plan": { - "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", - "promotionCode": "", - "product": "[parameters('plan').product]", - "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed solution." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed solution." - }, - "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the solution is deployed." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('solution', '2015-11-01-preview', 'full').location]" - } + "description": "Optional. Resource ID of the sub resource." } } }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" + } + } } }, - "outputs": { - "resourceId": { + "parameters": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed log analytics workspace." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } }, - "resourceGroupName": { + "computerName": { "type": "string", + "defaultValue": "[parameters('name')]", "metadata": { - "description": "The resource group of the deployed log analytics workspace." - }, - "value": "[resourceGroup().name]" + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } }, - "name": { + "vmSize": { "type": "string", "metadata": { - "description": "The name of the deployed log analytics workspace." - }, - "value": "[parameters('name')]" + "description": "Required. Specifies the size for the VMs." + } }, - "logAnalyticsWorkspaceId": { + "encryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { "type": "string", "metadata": { - "description": "The ID associated with the workspace." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" + }, + "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." }, - "value": "[reference('logAnalyticsWorkspace').customerId]" + "nullable": true }, - "location": { - "type": "string", + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The location the resource was deployed into." + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" + }, + "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." }, - "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" + "nullable": true }, - "systemAssignedMIPrincipalId": { - "type": "string", + "plan": { + "$ref": "#/definitions/planType", "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "type": "array", + "items": { + "$ref": "#/definitions/dataDiskType" }, - "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" + "nullable": true, + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } }, - "primarySharedKey": { + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "hibernationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables hibernation capability on the VM." + } + }, + "adminUsername": { "type": "securestring", + "nullable": true, "metadata": { - "description": "The primary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" + "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." + } }, - "secondarySharedKey": { + "adminPassword": { "type": "securestring", + "defaultValue": "", "metadata": { - "description": "The secondary shared key of the log analytics workspace." + "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." + } + }, + "userData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "items": { + "$ref": "#/definitions/vaultSecretGroupType" }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" - } - } - } - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the Log Analytics workspace." - }, - "value": "[reference('workspace').outputs.resourceId.value]" - }, - "name": { - "type": "string", - "metadata": { - "description": "Name of the Log Analytics workspace." - }, - "value": "[reference('workspace').outputs.name.value]" - }, - "location": { - "type": "string", - "metadata": { - "description": "Location of the workspace." - }, - "value": "[parameters('location')]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "Log Analytics workspace customer ID." - }, - "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" - } - } - } - } - }, - "applicationInsights": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appi-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "retentionInDays": { - "value": 365 - }, - "kind": { - "value": "web" - }, - "disableIpMasking": { - "value": false - }, - "flowType": { - "value": "Bluefield" - }, - "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17358780145253914698" - }, - "name": "Application Insights", - "description": "This component deploys an Application Insights instance." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } + "nullable": true, + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "Deallocate", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "publicKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/publicKeyType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "galleryApplications": { + "type": "array", + "items": { + "$ref": "#/definitions/vmGalleryApplicationType" }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "nullable": true, + "metadata": { + "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." + } + }, + "availabilityZone": { + "type": "int", + "allowedValues": [ + -1, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." + } + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "metadata": { + "description": "Required. Configures NICs and PIPs." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Recovery service vault name to add VMs to backup." + } + }, + "backupVaultResourceGroup": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "DefaultPolicy", + "metadata": { + "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + } + }, + "autoShutdownConfig": { + "$ref": "#/definitions/autoShutDownConfigType", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for auto-shutdown." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource Id of a maintenance configuration for this VM." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "dataCollectionRuleAssociations": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "$ref": "#/definitions/extensionCustomScriptConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionHostPoolRegistration": { + "type": "secureObject", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "extensionGuestConfigurationExtension": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "guestConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." + } + }, + "extensionGuestConfigurationExtensionProtectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "disablePasswordAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether password authentication should be disabled." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "enableHotpatching": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "items": { + "$ref": "#/definitions/additionalUnattendContentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRMListeners": { + "type": "array", + "items": { + "$ref": "#/definitions/winRMListenerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + }, + "capacityReservationGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." + } + }, + "networkAccessPolicy": { + "type": "string", + "defaultValue": "DenyAll", + "allowedValues": [ + "AllowAll", + "AllowPrivate", + "DenyAll" + ], + "metadata": { + "description": "Optional. Policy for accessing the disk via network." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Policy for controlling export on the disk." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application Insights." - } - }, - "applicationType": { - "type": "string", - "defaultValue": "web", - "allowedValues": [ - "web", - "other" - ], - "metadata": { - "description": "Optional. Application type." - } - }, - "workspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." - } - }, - "disableIpMasking": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable IP masking. Default value is set to true." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." - } - }, - "forceCustomerStorageForProfiler": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Force users to create their own storage account for profiler and debugger." - } - }, - "linkedStorageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Linked storage account resource ID." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": 365, - "allowedValues": [ - 30, - 60, - 90, - 120, - 180, - 270, - 365, - 550, - 730 - ], - "metadata": { - "description": "Optional. Retention period in days." - } - }, - "samplingPercentage": { - "type": "int", - "defaultValue": 100, - "minValue": 0, - "maxValue": 100, - "metadata": { - "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." - } - }, - "flowType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." - } - }, - "requestSource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." - } - }, - "kind": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." - } - }, - "immediatePurgeDataOn30Days": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Purge data immediately after 30 days." - } - }, - "ingestionMode": { - "type": "string", - "nullable": true, - "allowedValues": [ - "ApplicationInsights", - "ApplicationInsightsWithDiagnosticSettings", - "LogAnalytics" - ], - "metadata": { - "description": "Optional. Indicates the flow of the ingestion." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/components@2020-02-02#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", - "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", - "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "appInsights": { - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "Application_Type": "[parameters('applicationType')]", - "DisableIpMasking": "[parameters('disableIpMasking')]", - "DisableLocalAuth": "[parameters('disableLocalAuth')]", - "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", - "WorkspaceResourceId": "[parameters('workspaceResourceId')]", - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "RetentionInDays": "[parameters('retentionInDays')]", - "SamplingPercentage": "[parameters('samplingPercentage')]", - "Flow_Type": "[parameters('flowType')]", - "Request_Source": "[parameters('requestSource')]", - "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", - "IngestionMode": "[parameters('ingestionMode')]" - } - }, - "appInsights_roleAssignments": { - "copy": { - "name": "appInsights_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_diagnosticSettings": { - "copy": { - "name": "appInsights_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "linkedStorageAccount": { - "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appInsightsName": { - "value": "[parameters('name')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5059808225314360251" + "variables": { + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" + } + }, + { + "name": "additionalUnattendContentFormatted", + "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", + "input": { + "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", + "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", + "componentName": "Microsoft-Windows-Shell-Setup", + "passName": "OobeSystem" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", + "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" }, - "name": "Application Insights Linked Storage Account", - "description": "This component deploys an Application Insights Linked Storage Account." + "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", + "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" }, - "parameters": { - "appInsightsName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "managedDataDisks": { + "copy": { + "name": "managedDataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" + }, + "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", + "type": "Microsoft.Compute/disks", + "apiVersion": "2025-01-02", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", + "location": "[parameters('location')]", + "sku": { + "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" + }, + "properties": { + "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", + "creationData": { + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" + }, + "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", + "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "networkAccessPolicy": "[parameters('networkAccessPolicy')]" + }, + "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", + "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", + "plan": "[parameters('plan')]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", + "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", + "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", + "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", + "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", + "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", + "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", + "osType": "[parameters('osType')]", + "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", + "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", + "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", + "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", + "managedDisk": { + "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", + "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", + "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", + "hibernationEnabled": "[parameters('hibernationEnabled')]" + }, + "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" + } + } + ] + }, + "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", + "licenseType": "[parameters('licenseType')]", + "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" + }, + "dependsOn": [ + "managedDataDisks", + "vm_nic" + ] + }, + "vm_configurationAssignment": { + "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", + "type": "Microsoft.Maintenance/configurationAssignments", + "apiVersion": "2023-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[format('{0}assignment', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", + "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_autoShutdownConfiguration": { + "condition": "[not(empty(parameters('autoShutdownConfig')))]", + "type": "Microsoft.DevTestLab/schedules", + "apiVersion": "2018-09-15", + "name": "[format('shutdown-computevm-{0}', parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", + "properties": { + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", + "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "taskType": "ComputeVmShutdownTask", + "dailyRecurrence": { + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" + }, + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_dataCollectionRuleAssociations": { + "copy": { + "name": "vm_dataCollectionRuleAssociations", + "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" + }, + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2024-03-11", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", + "properties": { + "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "cseIdentity": { + "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", + "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" + }, + "AzureWindowsBaseline": { + "condition": "[not(empty(parameters('guestConfiguration')))]", + "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", + "apiVersion": "2024-04-05", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", + "location": "[parameters('location')]", + "properties": { + "guestConfiguration": "[parameters('guestConfiguration')]" + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + }, + "vm_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_roleAssignments": { + "copy": { + "name": "vm_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" + }, + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" + }, + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" + }, + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "lock": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "5982155361487304817" + } + }, + "definitions": { + "publicIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the public IP address configuration." + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the IP configuration." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" + }, + "enableTelemetry": { + "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" + }, + "ipTags": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5349747633189946992" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" + }, + "description": "Optional. The public IP address allocation method." + }, + "defaultValue": "Static" + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" + }, + "description": "Optional. IP address version." + }, + "defaultValue": "IPv4" + }, + "dnsSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" + }, + "description": "Optional. The DNS settings of the public IP address." + }, + "nullable": true + }, + "ipTags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" + }, + "description": "Optional. The list of tags associated with the public IP address." + }, + "nullable": true + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" + }, + "description": "Optional. Name of a public IP address SKU." + }, + "defaultValue": "Standard" + }, + "skuTier": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" + }, + "description": "Optional. Tier of a public IP address SKU." + }, + "defaultValue": "Regional" + }, + "ddosSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" + }, + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + }, + "nullable": true + }, + "deleteOption": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" + }, + "description": "Optional. The delete option for the public IP address." + }, + "nullable": true + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "272838238520810437" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface." + }, + "definitions": { + "networkInterfaceIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of load balancer backend address pools." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of references of LoadBalancerInboundNatRules." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the IP configuration is included." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Application Gateway Backend Address Pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The reference to gateway load balancer frontend IP." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Virtual Network Taps." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The resource ID of the deployed resource." + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backend address pool." + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application security group." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application gateway backend address pool." + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the sub resource." + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the inbound NAT rule." + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network tap." + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network interface IP configuration output." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationType" + }, + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "publicIp": { + "copy": { + "name": "publicIp", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", + "existing": true, + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", + "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", + "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", + "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", + "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", + "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", + "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", + "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2024-05-01', 'full').location]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "copy": { + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", + "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", + "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" + } + } + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the network interface." + }, + "value": "[reference('networkInterface').outputs.name.value]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "value": "[reference('networkInterface').outputs.ipConfigurations.value]" + } + } + } } }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Linked storage account resource ID." - } - } - }, - "resources": [ - { - "type": "microsoft.insights/components/linkedStorageAccounts", - "apiVersion": "2020-03-01-preview", - "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "vm_domainJoinExtension": { + "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", "properties": { - "linkedStorageAccount": "[parameters('storageAccountResourceId')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Linked Storage Account." - }, - "value": "ServiceProfiler" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Linked Storage Account." - }, - "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the agent pool was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "appInsights" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the application insights component." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application insights component." - }, - "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the application insights component was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "applicationId": { - "type": "string", - "metadata": { - "description": "The application ID of the application insights component." - }, - "value": "[reference('appInsights').AppId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('appInsights', '2020-02-02', 'full').location]" - }, - "instrumentationKey": { - "type": "string", - "metadata": { - "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." - }, - "value": "[reference('appInsights').InstrumentationKey]" - }, - "connectionString": { - "type": "string", - "metadata": { - "description": "Application Insights Connection String." - }, - "value": "[reference('appInsights').ConnectionString]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmManagedIdentity": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "identityName": { - "value": "[format('id-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "5270291310649425810" - } - }, - "parameters": { - "solutionName": { - "type": "string", - "metadata": { - "description": "Solution name used for resource naming." - } - }, - "identityName": { - "type": "string", - "defaultValue": "[format('id-{0}', parameters('solutionName'))]", - "metadata": { - "description": "Name of the managed identity." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region for the resource." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('identityName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." - }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "audiences": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." + "name": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" } }, - "issuer": { - "type": "string", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. The URL of the issuer to be trusted." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_domainJoinExtension" + ] + }, + "vm_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" } }, - "subject": { - "type": "string", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. The identifier of the external identity." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." - } + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] }, - "lockType": { - "type": "object", + "vm_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" } }, - "notes": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Specify the notes of the lock." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } + "dependsOn": [ + "vm", + "vm_microsoftAntiMalwareExtension" + ] }, - "roleAssignmentType": { - "type": "object", + "vm_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, + "settings": { + "value": { + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] }, - "isolationScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], - "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "vm_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 + } }, + "dependsOn": [ + "vm", + "vm_dependencyAgentExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" + "location": { + "value": "[parameters('location')]" }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + "publisher": { + "value": "Microsoft.Powershell" }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + "type": { + "value": "DSC" }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "1387931959101373036" + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, "parameters": { - "userAssignedIdentityName": { + "virtualMachineName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." } }, "name": { "type": "string", "metadata": { - "description": "Required. The name of the secret." + "description": "Required. The name of the virtual machine extension." } }, - "audiences": { - "type": "array", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + "description": "Optional. The location the extension is deployed to." } }, - "issuer": { + "publisher": { "type": "string", "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + "description": "Required. The name of the extension handler publisher." } }, - "subject": { + "type": { "type": "string", "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true } }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" } } - ], + }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the federated identity credential." + "description": "The name of the extension." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the federated identity credential." + "description": "The resource ID of the extension." }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the federated identity credential was created in." + "description": "The name of the Resource Group the extension was created in." }, "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } }, "dependsOn": [ - "userAssignedIdentity" + "vm", + "vm_networkWatcherAgentExtension" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Principal ID of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "Client ID of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" - }, - "name": { - "type": "string", - "metadata": { - "description": "Name of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" - } - } - } - } - }, - "avmContainerRegistry": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "name": { - "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "acrPullPrincipalIds": { - "value": [ - "[reference('avmContainerRegistryReader').outputs.principalId.value]" - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enablePrivateNetworking": { - "value": "[parameters('enablePrivateNetworking')]" - }, - "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", - "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value)), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8138805991948000285" - } - }, - "parameters": { - "solutionName": { - "type": "string", - "metadata": { - "description": "Solution name used for naming convention." - } - }, - "name": { - "type": "string", - "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", - "metadata": { - "description": "Name of the container registry." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region for deployment." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Resource tags." - } - }, - "sku": { - "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Standard", - "Premium" - ], - "metadata": { - "description": "SKU for the container registry." - } - }, - "adminUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable admin user for the registry." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Public network access setting." - } - }, - "exportPolicyStatus": { - "type": "string", - "defaultValue": "enabled", - "metadata": { - "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." - } - }, - "acrPullPrincipalIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Principal IDs to assign AcrPull role." - } - }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable private networking." - } - }, - "privateEndpointSubnetId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Subnet resource ID for private endpoint." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Private DNS zone resource IDs for private endpoint." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable Azure telemetry collection." - } - } - }, - "variables": { - "copy": [ - { - "name": "roleAssignments", - "count": "[length(parameters('acrPullPrincipalIds'))]", - "input": { - "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", - "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", - "principalType": "ServicePrincipal" - } - }, - { - "name": "dnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneResourceIds'))]", - "input": { - "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", - "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" - } - } - ], - "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", - "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "acrSku": { - "value": "[parameters('sku')]" - }, - "acrAdminUserEnabled": { - "value": "[parameters('adminUserEnabled')]" - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - }, - "exportPolicyStatus": { - "value": "[parameters('exportPolicyStatus')]" - }, - "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", - "privateEndpoints": { - "value": "[variables('privateEndpointConfig')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1509121545318808417" }, - "name": "Azure Container Registries (ACR)", - "description": "This module deploys an Azure Container Registry (ACR)." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", + "vm_customScriptExtension": { + "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" + }, + "provisionAfterExtensions": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettingsFromKeyVault": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" + }, + "settings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" + }, + "protectedSettings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" } }, - "groupId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true } }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "__bicep_export!": true - } + "dependsOn": [ + "cseIdentity", + "vm" + ] }, - "credentialSetType": { - "type": "object", + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a credential set." - } - }, - "scopeMapsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the scope map." + "name": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" } }, - "actions": { - "type": "array", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" }, - "description": "Required. The list of scoped permissions for registry artifacts." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The user friendly description of the scope map." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a scope map." - } - }, - "cacheRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cache rule." - } + "dependsOn": [ + "vm", + "vm_customScriptExtension" + ] }, - "replicationType": { - "type": "object", + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" } }, - "tags": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" }, - "description": "Optional. Tags of the resource." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } - }, - "zoneRedundancy": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } }, - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } }, - "nullable": true + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replication." - } + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] }, - "taskType": { - "type": "object", + "vm_hostPoolRegistrationExtension": { + "condition": "[parameters('extensionHostPoolRegistration').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the task." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.PowerShell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", + "properties": { + "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", + "aadJoin": true + } + } + }, + "protectedSettings": { + "value": { + "properties": { + "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" + } + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" } }, - "tags": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" }, - "description": "Optional. Tags of the resource." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } }, - "description": "Optional. The platform properties for the task." - }, - "nullable": true - }, - "step": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } }, - "description": "Optional. The step properties for the task." - }, - "nullable": true - }, - "trigger": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } }, - "description": "Optional. The trigger properties for the task." - }, - "nullable": true - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } }, - "description": "Optional. The status of the task at the time the operation was called." + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } }, - "nullable": true - }, - "timeout": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." - } - }, - "agentConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" }, - "description": "Optional. The agent configuration for the task." + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } }, - "nullable": true - }, - "agentPoolName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." - } - }, - "isSystemTask": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." - } - }, - "logTemplate": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The log template for the task to use when creating logs in Log Analytics." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a task." - } + "dependsOn": [ + "vm", + "vm_nvidiaGpuDriverWindowsExtension" + ] }, - "tokenType": { - "type": "object", + "vm_azureGuestConfigurationExtension": { + "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the token." - } - }, - "scopeMapResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the scope map which defines the permissions for this token." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" - }, - "description": "Optional. The status of the token at the time the operation was called." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" }, - "nullable": true - }, - "credentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" + "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." - } - } - } - }, - "webhookType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "string", - "metadata": { - "description": "Required. The service URI for the webhook to post notifications." - } - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" - }, - "description": "Optional. The status of the webhook at the time the operation was called." + "publisher": { + "value": "Microsoft.GuestConfiguration" }, - "nullable": true - }, - "action": { - "type": "array", - "items": { - "type": "string" + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" }, - "nullable": true, - "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, + "protectedSettings": { + "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" } }, - "tags": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" }, - "description": "Optional. Tags of the resource." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, - "nullable": true - }, - "customHeaders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } }, - "description": "Optional. Custom headers that will be added to the webhook notifications." + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } }, - "nullable": true - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a webhook." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "dependsOn": [ + "vm", + "vm_hostPoolRegistrationExtension" + ] }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", + "vm_backup": { + "condition": "[not(empty(parameters('backupVaultName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('backupVaultResourceGroup')]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyId": { + "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + }, + "protectedItemType": { + "value": "Microsoft.Compute/virtualMachines" + }, + "protectionContainerName": { + "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "recoveryVaultName": { + "value": "[parameters('backupVaultName')]" + }, + "sourceResourceId": { + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" } }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17448691641471706096" + }, + "name": "Recovery Service Vaults Protection Container Protected Item", + "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + }, + "parameters": { + "name": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. Name of the resource." } }, - "memberName": { + "protectionContainerName": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." } }, - "privateIPAddress": { + "recoveryVaultName": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "protectedItemType": { + "type": "string", + "allowedValues": [ + "AzureFileShareProtectedItem", + "AzureVmWorkloadSAPAseDatabase", + "AzureVmWorkloadSAPHanaDatabase", + "AzureVmWorkloadSQLDatabase", + "DPMProtectedItem", + "GenericProtectedItem", + "MabFileFolderProtectedItem", + "Microsoft.ClassicCompute/virtualMachines", + "Microsoft.Compute/virtualMachines", + "Microsoft.Sql/servers/databases" + ], + "metadata": { + "description": "Required. The backup item type." + } + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Required. ID of the backup policy with which this item is backed up." + } + }, + "sourceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource to back up." } } }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + "resources": [ + { + "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", + "apiVersion": "2025-02-01", + "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "protectedItemType": "[parameters('protectedItemType')]", + "policyId": "[parameters('policyId')]", + "sourceResourceId": "[parameters('sourceResourceId')]" } } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the protected item was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the protected item." + }, + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The Name of the protected item." + }, + "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" + } } } }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + } + }, + "outputs": { + "name": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The name of the VM." + }, + "value": "[parameters('name')]" }, - "authCredentialsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } - }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." - } - }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "The type for auth credentials.", - "__bicep_imported_from!": { - "sourceTemplate": "credential-set/main.bicep" - } - } + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." }, + "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2024-07-01', 'full').location]" }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationOutputType" }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "description": "The list of NIC configurations of the virtual machine." + }, + "copy": { + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", + "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" } } + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the virtual machine." + }, + "value": "[reference('virtualMachine').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the virtual machine." + }, + "value": "[reference('virtualMachine').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.maintenance-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.data-collection-rule.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.maintenance-configuration.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('mc-{0}', variables('jumpboxVmName'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionProperties": { + "value": { + "InGuestPatchMode": "User" + } + }, + "maintenanceScope": { + "value": "InGuestPatch" + }, + "maintenanceWindow": { + "value": { + "startDateTime": "2024-06-16 00:00", + "duration": "03:55", + "timeZone": "W. Europe Standard Time", + "recurEvery": "1Day" + } + }, + "visibility": { + "value": "Custom" + }, + "installPatches": { + "value": { + "rebootSetting": "IfRequired", + "windowsParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + }, + "linuxParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + } + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17869572276338216144" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the maintenance configuration." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "extensionProperties": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Extension properties for the maintenance configuration." + } + }, + "maintenanceScope": { + "type": "string", + "metadata": { + "description": "Maintenance scope for the configuration." + } + }, + "maintenanceWindow": { + "type": "object", + "metadata": { + "description": "Maintenance window configuration." + } + }, + "visibility": { + "type": "string", + "defaultValue": "Custom", + "metadata": { + "description": "Visibility of the maintenance configuration." + } + }, + "installPatches": { + "type": "object", + "metadata": { + "description": "Install patches configuration." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.maintenance.maintenance-configuration.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionProperties": { + "value": "[parameters('extensionProperties')]" + }, + "maintenanceScope": { + "value": "[parameters('maintenanceScope')]" + }, + "maintenanceWindow": { + "value": "[parameters('maintenanceWindow')]" + }, + "visibility": { + "value": "[parameters('visibility')]" + }, + "installPatches": { + "value": "[parameters('installPatches')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14895287194406877557" }, + "name": "Maintenance Configurations", + "description": "This module deploys a Maintenance Configuration." + }, + "definitions": { "lockType": { "type": "object", "properties": { @@ -24820,197 +20217,6 @@ } } }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityOnlySysAssignedType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, "roleAssignmentType": { "type": "object", "properties": { @@ -25090,239 +20296,32 @@ "parameters": { "name": { "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. Name of your Azure Container Registry." - } - }, - "acrAdminUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable admin user that have push / pull permission to the registry." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "autoGeneratedDomainNameLabelScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse", - "Unsecure" - ], - "metadata": { - "description": "Optional. The domain name label reuse scope." - } - }, - "roleAssignmentMode": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AbacRepositoryPermissions", - "LegacyRegistryPermissions" - ], - "metadata": { - "description": "Optional. The registry permissions role assignment mode." - } - }, - "acrSku": { - "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Premium", - "Standard" - ], - "metadata": { - "description": "Optional. Tier of your Azure container registry." - } - }, - "exportPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the export policy is enabled or not." - } - }, - "quarantinePolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "trustPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "retentionPolicyStatus": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the retention policy is enabled or not." - } - }, - "retentionPolicyDays": { - "type": "int", - "defaultValue": 15, - "metadata": { - "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." - } - }, - "azureADAuthenticationAsArmPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." - } - }, - "softDeletePolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. Soft Delete policy status. Default is disabled." - } - }, - "softDeletePolicyDays": { - "type": "int", - "defaultValue": 7, "metadata": { - "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + "description": "Required. Maintenance Configuration Name." } }, - "dataEndpointEnabled": { + "enableTelemetry": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "networkRuleBypassOptions": { - "type": "string", - "defaultValue": "AzureServices", - "allowedValues": [ - "AzureServices", - "None" - ], - "metadata": { - "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." - } - }, - "networkRuleSetDefaultAction": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], + "defaultValue": true, "metadata": { - "description": "Optional. The default action of allow or deny when no other rules match." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "networkRuleSetIpRules": { - "type": "array", - "nullable": true, + "extensionProperties": { + "type": "object", "metadata": { - "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" + }, + "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." - } + "defaultValue": {} }, - "zoneRedundancy": { + "location": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } - }, - "replications": { - "type": "array", - "items": { - "$ref": "#/definitions/replicationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All replications to create." - } - }, - "webhooks": { - "type": "array", - "items": { - "$ref": "#/definitions/webhookType" - }, - "nullable": true, + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. All webhooks to create." + "description": "Optional. Location for all Resources." } }, "lock": { @@ -25332,103 +20331,72 @@ "description": "Optional. The lock settings of the service." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "tags": { - "type": "object", + "maintenanceScope": { + "type": "string", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" }, - "description": "Optional. Tags of the resource." + "description": "Optional. Gets or sets maintenanceScope of the configuration." }, - "nullable": true + "defaultValue": "Host" }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "maintenanceWindow": { + "type": "object", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" + }, + "description": "Optional. Definition of a MaintenanceWindow." }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." - } - }, - "anonymousPullEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } + "defaultValue": {} }, - "cacheRules": { - "type": "array", - "items": { - "$ref": "#/definitions/cacheRuleType" - }, - "nullable": true, + "namespace": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Array of Cache Rules." + "description": "Optional. Gets or sets namespace of the resource." } }, - "credentialSets": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/credentialSetType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. Array of Credential Sets." + "description": "Optional. Array of role assignments to create." } }, - "scopeMaps": { - "type": "array", - "items": { - "$ref": "#/definitions/scopeMapsType" - }, - "nullable": true, + "tags": { + "type": "object", "metadata": { - "description": "Optional. Scope maps setting." - } - }, - "tokens": { - "type": "array", - "items": { - "$ref": "#/definitions/tokenType" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" + }, + "description": "Optional. Gets or sets tags of the resource." }, - "nullable": true, - "metadata": { - "description": "Optional. Tokens to create for the container registry." - } + "nullable": true }, - "tasks": { - "type": "array", - "items": { - "$ref": "#/definitions/taskType" + "visibility": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" + }, + "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." }, - "nullable": true, + "nullable": true + }, + "installPatches": { + "type": "object", "metadata": { - "description": "Optional. Array of ACR Tasks to create." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" + }, + "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." + }, + "defaultValue": {} } }, "variables": { @@ -25439,44 +20407,21 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { - "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", - "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", - "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", - "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", - "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", - "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", - "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", - "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", - "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", - "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", - "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" + } }, "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -25492,128 +20437,44 @@ } } }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "registry": { - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-06-01-preview", + "maintenanceConfiguration": { + "type": "Microsoft.Maintenance/maintenanceConfigurations", + "apiVersion": "2023-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", - "identity": "[variables('identity')]", "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('acrSku')]" - }, "properties": { - "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", - "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", - "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", - "roleAssignmentMode": "[parameters('roleAssignmentMode')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", - "policies": { - "azureADAuthenticationAsArmPolicy": { - "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" - }, - "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", - "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", - "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", - "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", - "softDeletePolicy": { - "retentionDays": "[parameters('softDeletePolicyDays')]", - "status": "[parameters('softDeletePolicyStatus')]" - } - }, - "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", - "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", - "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", - "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", - "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] + "extensionProperties": "[parameters('extensionProperties')]", + "maintenanceScope": "[parameters('maintenanceScope')]", + "maintenanceWindow": "[parameters('maintenanceWindow')]", + "namespace": "[parameters('namespace')]", + "visibility": "[parameters('visibility')]", + "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" + } }, - "registry_lock": { + "maintenanceConfiguration_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "registry" - ] - }, - "registry_diagnosticSettings": { - "copy": { - "name": "registry_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "registry" + "maintenanceConfiguration" ] }, - "registry_roleAssignments": { + "maintenanceConfiguration_roleAssignments": { "copy": { - "name": "registry_roleAssignments", + "name": "maintenanceConfiguration_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -25624,731 +20485,1011 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "registry" + "maintenanceConfiguration" ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Maintenance Configuration." + }, + "value": "[parameters('name')]" }, - "registry_scopeMaps": { - "copy": { - "name": "registry_scopeMaps", - "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Maintenance Configuration." }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Maintenance Configuration was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the Maintenance Configuration was created in." + }, + "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the maintenance configuration." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.maintenance.maintenance-configuration.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the maintenance configuration." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.maintenance.maintenance-configuration.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + { + "copy": { + "name": "avmPrivateDnsZones", + "count": "[length(variables('privateDnsZones'))]", + "mode": "serial", + "batchSize": 5 + }, + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), copyIndex()), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZones')[copyIndex()]]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "virtualNetworkLinks": { + "value": [ + { + "virtualNetworkResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12448195195174935873" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the private DNS zone." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "virtualNetworkLinks": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Virtual network link configurations for the private DNS zone." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-dns-zone.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "virtualNetworkLinks": { + "value": "[parameters('virtualNetworkLinks')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18337341331267624582" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone." + }, + "definitions": { + "aType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" - }, - "actions": { - "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." }, - "registryName": { - "value": "[parameters('name')]" + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "aRecords": { + "type": "array", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3787322352564227867" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" }, - "name": "Container Registries scope maps", - "description": "This module deploys an Azure Container Registry (ACR) scope map." + "description": "Optional. The list of A records in the record set." }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", - "metadata": { - "description": "Optional. The name of the scope map." - } - }, - "actions": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of scoped permissions for registry artifacts." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The user friendly description of the scope map." - } + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the A record." + } + }, + "aaaaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } + "description": "Optional. The metadata of the record." }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "scopeMap": { - "type": "Microsoft.ContainerRegistry/registries/scopeMaps", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "actions": "[parameters('actions')]", - "description": "[parameters('description')]" - } - } + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the scope map." - }, - "value": "[parameters('name')]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aaaaRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the scope map was created in." - }, - "value": "[resourceGroup().name]" + "description": "Optional. The list of AAAA records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the AAAA record." + } + }, + "cnameType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the scope map." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" - } + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } + }, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. The CNAME record in the record set." + }, + "nullable": true } }, - "dependsOn": [ - "registry" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type for the CNAME record." + } }, - "registry_replications": { - "copy": { - "name": "registry_replications", - "count": "[length(coalesce(parameters('replications'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "mxType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." }, - "location": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "regionEndpointEnabled": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." }, - "zoneRedundancy": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the MX record." + } + }, + "ptrType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "ptrRecords": { + "type": "array", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "6219097750044645017" + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" }, - "name": "Azure Container Registry (ACR) Replications", - "description": "This module deploys an Azure Container Registry (ACR) Replication." + "description": "Optional. The list of PTR records in the record set." }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the PTR record." + } + }, + "soaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" }, - "zoneRedundancy": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } + "description": "Optional. The SOA record in the record set." }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SOA record." + } + }, + "srvType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "srvRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" }, - "replication": { - "type": "Microsoft.ContainerRegistry/registries/replications", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", - "zoneRedundancy": "[parameters('zoneRedundancy')]" - } - } + "description": "Optional. The list of SRV records in the record set." }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the replication." - }, - "value": "[parameters('name')]" + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SRV record." + } + }, + "txtType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the replication." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the replication was created in." - }, - "value": "[resourceGroup().name]" + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the TXT record." + } + }, + "virtualNetworkLinkType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Optional. The resource name." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the virtual network to link." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Region where the resource lives." + } + }, + "registrationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('replication', '2025-11-01', 'full').location]" - } + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "resolutionPolicy": { + "type": "string", + "allowedValues": [ + "Default", + "NxDomainRedirect" + ], + "nullable": true, + "metadata": { + "description": "Optional. The resolution type of the private-dns-zone fallback machanism." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network link." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, - "dependsOn": [ - "registry" - ] + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "a": { + "type": "array", + "items": { + "$ref": "#/definitions/aType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of A records." + } }, - "registry_credentialSets": { - "copy": { - "name": "registry_credentialSets", - "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + "aaaa": { + "type": "array", + "items": { + "$ref": "#/definitions/aaaaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of AAAA records." + } + }, + "cname": { + "type": "array", + "items": { + "$ref": "#/definitions/cnameType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of CNAME records." + } + }, + "mx": { + "type": "array", + "items": { + "$ref": "#/definitions/mxType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of MX records." + } + }, + "ptr": { + "type": "array", + "items": { + "$ref": "#/definitions/ptrType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of PTR records." + } + }, + "soa": { + "type": "array", + "items": { + "$ref": "#/definitions/soaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SOA records." + } + }, + "srv": { + "type": "array", + "items": { + "$ref": "#/definitions/srvType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SRV records." + } + }, + "txt": { + "type": "array", + "items": { + "$ref": "#/definitions/txtType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of TXT records." + } + }, + "virtualNetworkLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkLinkType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "managedIdentities": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" - }, - "authCredentials": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" - }, - "loginServer": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13412699468141336519" - }, - "name": "Container Registries Credential Sets", - "description": "This module deploys an ACR Credential Set." - }, - "definitions": { - "authCredentialsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } - }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." - } - }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for auth credentials." - } - }, - "managedIdentityOnlySysAssignedType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" - }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "credentialSet": { - "type": "Microsoft.ContainerRegistry/registries/credentialSets", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", - "properties": { - "authCredentials": "[parameters('authCredentials')]", - "loginServer": "[parameters('loginServer')]" - } - } - }, + "resources": [], "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Credential Set." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Credential Set." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Credential Set." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "registry" + "privateDnsZone" ] }, - "registry_cacheRules": { + "privateDnsZone_roleAssignments": { "copy": { - "name": "registry_cacheRules", - "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + "name": "privateDnsZone_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "registryName": { - "value": "[parameters('name')]" - }, - "sourceRepository": { - "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" - }, - "targetRepository": { - "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" - }, - "credentialSetResourceId": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1319901650921923538" - }, - "name": "Container Registry Cache", - "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "defaultValue": "[parameters('sourceRepository')]", - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "cacheRule": { - "type": "Microsoft.ContainerRegistry/registries/cacheRules", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "sourceRepository": "[parameters('sourceRepository')]", - "targetRepository": "[parameters('targetRepository')]", - "credentialSetResourceId": "[parameters('credentialSetResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Cache Rule." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Cache Rule." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cache Rule." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" - } - } - } + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "registry", - "registry_credentialSets" + "privateDnsZone" ] }, - "registry_tokens": { - "copy": { - "name": "registry_tokens", - "count": "[length(coalesce(parameters('tokens'), createArray()))]" + "privateDnsZone_A": { + "copy": { + "name": "privateDnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" }, - "registryName": { - "value": "[parameters('name')]" + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" }, - "scopeMapResourceId": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" + "metadata": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" }, - "status": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -26361,68 +21502,171 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "5970335582661416899" + "version": "0.41.2.15936", + "templateHash": "7372385900111002873" }, - "name": "Container Registries Tokens", - "description": "Deploys an Azure Container Registry (ACR) Token." + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." }, - "parameters": { - "registryName": { - "type": "string", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "name": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", - "minLength": 5, - "maxLength": 50, "metadata": { - "description": "Required. The name of the token." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "scopeMapResourceId": { + "name": { "type": "string", "metadata": { - "description": "Required. The resource ID of the scope map to which the token will be associated with." + "description": "Required. The name of the A record." } }, - "status": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], + "aRecords": { + "type": "array", "metadata": { - "description": "Optional. The status of the token. Default is enabled." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true }, - "credentials": { + "metadata": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" }, - "description": "Optional. The credentials associated with the token for authentication." + "description": "Optional. The metadata attached to the record set." }, "nullable": true }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -26438,111 +21682,105 @@ } } }, - "registry": { + "privateDnsZone": { "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "token": { - "type": "Microsoft.ContainerRegistry/registries/tokens", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "scopeMapId": "[parameters('scopeMapResourceId')]", - "status": "[parameters('status')]", - "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the token." + "description": "The name of the deployed A record." }, "value": "[parameters('name')]" }, - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the resource group the token was created in." + "description": "The resource ID of the deployed A record." }, - "value": "[resourceGroup().name]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" }, - "resourceId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource ID of the token." + "description": "The resource group of the deployed A record." }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "registry", - "registry_scopeMaps" + "privateDnsZone" ] }, - "registry_tasks": { + "privateDnsZone_AAAA": { "copy": { - "name": "registry_tasks", - "count": "[length(coalesce(parameters('tasks'), createArray()))]" + "name": "privateDnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "registryName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "platform": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" - }, - "step": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" - }, - "trigger": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" - }, - "timeout": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" - }, - "agentConfiguration": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" - }, - "agentPoolName": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" }, - "isSystemTask": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" }, - "logTemplate": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "managedIdentities": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -26555,190 +21793,171 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2468771835002458415" + "version": "0.41.2.15936", + "templateHash": "14405855828972373002" }, - "name": "Container Registries Tasks", - "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." }, "definitions": { - "managedIdentityAllType": { + "roleAssignmentType": { "type": "object", "properties": { - "systemAssigned": { - "type": "bool", + "name": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } }, "parameters": { - "registryName": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, "name": { "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. The name of the task." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Required. The name of the AAAA record." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" - }, - "description": "Optional. The platform properties against which the task has to run." - }, - "nullable": true - }, - "step": { - "type": "object", + "aaaaRecords": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" }, - "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + "description": "Optional. The list of AAAA records in the record set." }, "nullable": true }, - "trigger": { + "metadata": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" }, - "description": "Optional. The properties that describe all triggers for the task." + "description": "Optional. The metadata attached to the record set." }, "nullable": true }, - "status": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. The current status of task." - } - }, - "timeout": { + "ttl": { "type": "int", "defaultValue": 3600, - "minValue": 300, - "maxValue": 28800, - "metadata": { - "description": "Optional. Run timeout in seconds." - } - }, - "agentConfiguration": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" - }, - "description": "Optional. The machine configuration of the run agent." - }, - "nullable": true - }, - "agentPoolName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The dedicated agent pool for the task." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "credentials": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" - }, - "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." - }, - "nullable": true - }, - "isSystemTask": { + "enableTelemetry": { "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The value of this property indicates whether the task resource is system task or not." - } - }, - "logTemplate": { - "type": "string", - "nullable": true, + "defaultValue": true, "metadata": { - "description": "Optional. The template that describes the repository and tag information for run log artifact." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Array of role assignments to create." } } }, "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -26754,117 +21973,105 @@ } } }, - "registry": { + "privateDnsZone": { "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "task": { - "type": "Microsoft.ContainerRegistry/registries/tasks", - "apiVersion": "2025-03-01-preview", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "agentConfiguration": "[parameters('agentConfiguration')]", - "agentPoolName": "[parameters('agentPoolName')]", - "credentials": "[parameters('credentials')]", - "isSystemTask": "[parameters('isSystemTask')]", - "logTemplate": "[parameters('logTemplate')]", - "platform": "[parameters('platform')]", - "status": "[parameters('status')]", - "step": "[parameters('step')]", - "timeout": "[parameters('timeout')]", - "trigger": "[parameters('trigger')]" + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the task." + "description": "The name of the deployed AAAA record." }, "value": "[parameters('name')]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the task was deployed into." - }, - "value": "[resourceGroup().name]" - }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the task." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "description": "The resource ID of the deployed AAAA record." }, - "value": "[reference('task', '2025-03-01-preview', 'full').location]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" }, - "systemAssignedMIPrincipalId": { + "resourceGroupName": { "type": "string", - "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "The resource group of the deployed AAAA record." }, - "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "registry" + "privateDnsZone" ] }, - "registry_webhooks": { + "privateDnsZone_CNAME": { "copy": { - "name": "registry_webhooks", - "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + "name": "privateDnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" - }, - "registryName": { + "privateDnsZoneName": { "value": "[parameters('name')]" }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "action": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" - }, - "customHeaders": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + "name": { + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" }, - "scope": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" }, - "status": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + "metadata": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" }, - "serviceUri": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -26877,90 +22084,127 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3200175097987099858" + "version": "0.41.2.15936", + "templateHash": "13818627461335065928" }, - "name": "Azure Container Registry (ACR) Webhooks", - "description": "This module deploys an Azure Container Registry (ACR) Webhook." + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}webhook', parameters('registryName'))]", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "securestring", + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Required. The service URI for the webhook to post notifications." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } - }, - "status": { + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The status of the webhook at the time the operation was called." - } - }, - "action": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [ - "chart_delete", - "chart_push", - "delete", - "push", - "quarantine" - ], "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Required. The name of the CNAME record." } }, - "tags": { + "cnameRecord": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" }, - "description": "Optional. Tags of the resource." + "description": "Optional. A CNAME record." }, "nullable": true }, - "customHeaders": { + "metadata": { "type": "object", - "nullable": true, "metadata": { - "description": "Optional. Custom headers that will be added to the webhook notifications." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true }, - "scope": { - "type": "string", - "nullable": true, + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, "enableTelemetry": { @@ -26969,14 +22213,42 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -26992,137 +22264,108 @@ } } }, - "registry": { + "privateDnsZone": { "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "webhook": { - "type": "Microsoft.ContainerRegistry/registries/webhooks", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "actions": "[parameters('action')]", - "customHeaders": "[parameters('customHeaders')]", - "scope": "[parameters('scope')]", - "serviceUri": "[parameters('serviceUri')]", - "status": "[parameters('status')]" + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] } }, "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the webhook." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "The name of the webhook." + "description": "The name of the deployed CNAME record." }, "value": "[parameters('name')]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Azure container registry." - }, - "value": "[resourceGroup().name]" - }, - "actions": { - "type": "array", - "metadata": { - "description": "The actions of the webhook." - }, - "value": "[reference('webhook').actions]" - }, - "status": { - "type": "string", - "metadata": { - "description": "The status of the webhook." - }, - "value": "[reference('webhook').status]" - }, - "provistioningState": { + "resourceId": { "type": "string", "metadata": { - "description": "The provisioning state of the webhook." + "description": "The resource ID of the deployed CNAME record." }, - "value": "[reference('webhook').provisioningState]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" }, - "location": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The resource group of the deployed CNAME record." }, - "value": "[reference('webhook', '2025-11-01', 'full').location]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "registry" + "privateDnsZone" ] }, - "registry_privateEndpoints": { + "privateDnsZone_MX": { "copy": { - "name": "registry_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "name": "privateDnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "privateDnsZoneName": { + "value": "[parameters('name')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "name": { + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -27133,98 +22376,303 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "18436885663402767850" + "templateHash": "2977624679479439942" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." }, "definitions": { - "privateDnsZoneGroupType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, + "roleDefinitionIdOrName": { + "type": "string", "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The description of the role assignment." } }, - "kind": { + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { "type": "string", "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" + "2.0" ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. Version of the condition." } }, - "notes": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } } }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_PTR": { + "copy": { + "name": "privateDnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + }, + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15286275176817336979" }, + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." + }, + "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -27296,80 +22744,56 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "customNetworkInterfaceName": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Required. The name of the PTR record." } }, - "ipConfigurations": { - "type": "array", + "metadata": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. The metadata attached to the record set." }, "nullable": true }, - "ipVersionType": { - "type": "string", + "ptrRecords": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + "description": "Optional. The list of PTR records in the record set." }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } + "nullable": true }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Enable/Disable usage telemetry for module." } }, "roleAssignments": { @@ -27381,53 +22805,6 @@ "metadata": { "description": "Optional. Array of role assignments to create." } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } } }, "variables": { @@ -27440,23 +22817,20 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -27472,56 +22846,31 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" } }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { + "PTR_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "PTR_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -27532,2636 +22881,2622 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "PTR" ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SOA": { + "copy": { + "name": "privateDnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" + }, + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4837447718856535826" + }, + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "principalId": { + "type": "string", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. A SOA record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "SOA" ] } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." + "description": "The name of the deployed SOA record." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "The resource ID of the deployed SOA record." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The resource group of the deployed SOA record." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SRV": { + "copy": { + "name": "privateDnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15028912535488490265" }, - "location": { + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } }, - "customDnsConfigs": { - "type": "array", + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" }, - "description": "The custom DNS configurations of the private endpoint." + "description": "Optional. The metadata attached to the record set." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "nullable": true }, - "networkInterfaceResourceIds": { + "srvRecords": { "type": "array", - "items": { - "type": "string" - }, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "nullable": true }, - "groupId": { - "type": "string", - "nullable": true, + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "registry", - "registry_replications" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Azure container registry." - }, - "value": "[parameters('name')]" - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "The reference to the Azure container registry." - }, - "value": "[reference('registry').loginServer]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Azure container registry." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Azure container registry." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('registry', '2025-06-01-preview', 'full').location]" - }, - "credentialSetsSystemAssignedMIPrincipalIds": { - "type": "array", - "metadata": { - "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" - } - }, - "credentialSetsResourceIds": { - "type": "array", - "metadata": { - "description": "The Resource IDs of the ACR Credential Sets." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the Azure container registry." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container registry." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "The login server URL." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container registry." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" - } - } - } - }, - "dependsOn": [ - "avmContainerRegistryReader", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", - "virtualNetwork" - ] - }, - "avmStorageAccount": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "minimumTlsVersion": { - "value": "TLS1_2" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", - "ipRules": [] - } - }, - "requireInfrastructureEncryption": { - "value": true - }, - "supportsHttpsTrafficOnly": { - "value": true - }, - "accessTier": { - "value": "Hot" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1254456195180100771" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoints output." - } - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_TXT": { + "copy": { + "name": "privateDnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network configuration." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey1 secret name to create." - } - }, - "connectionString1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString1 secret name to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey2 secret name to create." - } - }, - "connectionString2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString2 secret name to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the exported secrets." - } - }, - "localUserType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The local user home directory." - } - }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" - }, - "metadata": { - "description": "Required. The permission scopes of the local user." - } - }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a local user." - } - }, - "blobServiceType": { - "type": "object", - "properties": { - "automaticSnapshotPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." - } - }, - "changeFeedEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." - } - }, - "changeFeedRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 146000, - "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." - } - }, - "containerDeleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." - } - }, - "containerDeleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." - } - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/blobCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "defaultServiceVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." - } - }, - "deleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob soft delete." - } - }, - "deleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." - } - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "isVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." - } - }, - "versionDeletePolicyDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." - } - }, - "lastAccessTimeTrackingPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." - } - }, - "restorePolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." - } - }, - "restorePolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Blob containers to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a blob service." - } - }, - "fileServiceType": { - "type": "object", - "properties": { - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" + }, + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7641583415110009849" + }, + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] }, - "description": "Optional. Protocol settings for file service." + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7392770862892927923" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } }, - "nullable": true - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" }, - "description": "Optional. The service properties for soft delete." - }, - "nullable": true - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/fileCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a file service." - } - }, - "queueServiceType": { - "type": "object", - "properties": { - "queues": { - "type": "array", - "items": { - "$ref": "#/definitions/queueType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Queues to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/queueCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a queue service." - } - }, - "tableServiceType": { - "type": "object", - "properties": { - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/tableCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a table service." - } - }, - "objectReplicationPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." - } - }, - "destinationStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the destination storage account." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. The storage account object replication rules." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy." - } - }, - "_1.immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - } - }, - "metadata": { - "description": "The type for an immutability policy.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/container/main.bicep" - } - } - }, - "_2.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "name": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" }, - "memberName": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" }, - "privateIPAddress": { + "location": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." } } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the private DNS zone." }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.network.private-dns-zone.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "name": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "description": "Name of the private DNS zone." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.network.private-dns-zone.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.private-endpoint.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": { + "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", + "properties": { + "privateLinkServiceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]", + "groupIds": [ + "account" + ] } } - }, - "_2.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "name": "ai-services-dns-zone-cognitiveservices", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cognitiveServices), 64)), '2025-04-01').outputs.resourceId.value]" }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } + { + "name": "ai-services-dns-zone-openai", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').openAI), 64)), '2025-04-01').outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-aiservices", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').aiServices), 64)), '2025-04-01').outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-contentunderstanding", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').contentUnderstanding), 64)), '2025-04-01').outputs.resourceId.value]" } - }, + ] + } + }, + "subnetResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2838568424679140846" + } + }, + "parameters": { + "name": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "Name of the private endpoint." } }, - "_2.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, + "location": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "Azure region for the resource." } }, - "blobCorsRuleType": { + "tags": { "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep", - "originalIdentifier": "corsRuleType" - } + "description": "Tags to apply to the resource." } }, - "containerType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } - }, - "immutabilityPolicy": { - "$ref": "#/definitions/_1.immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. A name-value pair to associate with the container as metadata." - }, - "nullable": true - }, - "publicAccess": { - "type": "string", - "allowedValues": [ - "Blob", - "Container", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, + "customNetworkInterfaceName": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "The type of a storage container.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep" - } + "description": "Optional. Name of the custom network interface." } }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, + "privateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "Private link service connections." } }, - "diagnosticSettingFullType": { + "privateDnsZoneGroup": { "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Private DNS zone group configuration." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the subnet used by the private endpoint." + } + } + }, + "resources": { + "privateEndpoint": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-endpoint.{0}', parameters('name')), 64)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": "[if(not(empty(parameters('customNetworkInterfaceName'))), createObject('value', parameters('customNetworkInterfaceName')), createObject('value', null()))]", + "privateLinkServiceConnections": { + "value": "[parameters('privateLinkServiceConnections')]" + }, + "privateDnsZoneGroup": { + "value": "[parameters('privateDnsZoneGroup')]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" } }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "fileCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." - } - }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, - "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a file share.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { "type": "array", "items": { "type": "string" }, - "nullable": true, "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" }, - "minCreationTime": { + "groupId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." } } - }, - "metadata": { - "description": "The type of an object replication policy rule.", - "__bicep_imported_from!": { - "sourceTemplate": "object-replication-policy/policy/main.bicep" - } } - }, - "permissionScopeType": { - "type": "object", - "properties": { - "permissions": { - "type": "string", - "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." - } - }, - "resourceName": { - "type": "string", - "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." - } - } - }, + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } + "description": "Resource ID of the private endpoint." }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "value": "[reference('privateEndpoint').outputs.resourceId.value]" }, - "queueCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, + "name": { + "type": "string", "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "queueType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the queue." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } + "description": "Name of the private endpoint." }, + "value": "[reference('privateEndpoint').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').openAI), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').contentUnderstanding), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').aiServices), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cognitiveServices), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { + "type": "string", "metadata": { - "description": "The type for a queue.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep" - } + "description": "Solution name used for resource naming." } }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "Name of the managed identity." } }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_2.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, + "location": { + "type": "string", "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "Azure region for the resource." } }, - "sshAuthorizedKeyType": { + "tags": { "type": "object", - "properties": { - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description used to store the function/usage of the key." - } - }, - "key": { - "type": "securestring", - "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." - } - } - }, + "defaultValue": {}, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } + "description": "Tags to apply to the resource." } }, - "tableCorsRuleType": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('identityName')]" }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" + "location": { + "value": "[parameters('location')]" }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "definitions": { + "federatedIdentityCredentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } } } - }, - "metadata": { - "description": "The type for a table.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep" - } } } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "extendedLocationZone": { + ], + "outputs": { + "resourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "description": "Resource ID of the managed identity." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "kind": { - "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_ZRS", - "Standard_GRS", - "Standard_GZRS", - "Standard_RAGRS", - "Standard_RAGZRS", - "StandardV2_LRS", - "StandardV2_ZRS", - "StandardV2_GRS", - "StandardV2_GZRS", - "Premium_LRS", - "Premium_ZRS", - "PremiumV2_LRS", - "PremiumV2_ZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "Cold" - ], - "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." - } + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "largeFileSharesState": { + "principalId": { "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" - }, - "description": "Optional. Provides the identity based authentication settings for Azure Files." + "description": "Principal ID of the managed identity." }, - "nullable": true - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, + "clientId": { + "type": "string", "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" + "description": "Client ID of the managed identity." }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" }, - "managementPolicyRules": { - "type": "array", + "name": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Optional. The Storage Account ManagementPolicies Rules." + "description": "Name of the managed identity." }, - "nullable": true - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, - "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." - } - }, - "customDomainName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." - } - }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + "description": "Solution name used for resource naming." } }, - "dnsEndpointType": { + "identityName": { "type": "string", - "nullable": true, - "allowedValues": [ - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "$ref": "#/definitions/blobServiceType", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "$ref": "#/definitions/fileServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "$ref": "#/definitions/queueServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "$ref": "#/definitions/tableServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. Table service and tables to create." - } - }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + "description": "Name of the managed identity." } }, - "minimumTlsVersion": { + "location": { "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_2", - "TLS1_3" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." - } - }, - "enableSftp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "localUsers": { - "type": "array", - "items": { - "$ref": "#/definitions/localUserType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Local users to deploy for SFTP authentication." - } - }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables local users feature, if set to true." - } - }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Azure region for the resource." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, "enableTelemetry": { "type": "bool", @@ -30169,288 +25504,13 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "allowedCopyScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AAD", - "PrivateLink" - ], - "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "sasExpirationAction": { - "type": "string", - "defaultValue": "Log", - "allowedValues": [ - "Block", - "Log" - ], - "metadata": { - "description": "Optional. The SAS expiration action. Allowed values are Block and Log." - } - }, - "keyType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], - "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "immutableStorageWithVersioning": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" - }, - "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." - }, - "nullable": true - }, - "objectReplicationPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Object replication policies for the storage account." - } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", - "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2025-05-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_roleAssignments": { - "copy": { - "name": "storageAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -30458,42 +25518,16 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('identityName')]" }, "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[parameters('location')]" }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "value": "[parameters('tags')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -30503,36 +25537,47 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." }, "definitions": { - "privateDnsZoneGroupType": { + "federatedIdentityCredentialType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Required. The name of the federated identity credential." } }, - "privateDnsZoneGroupConfigs": { + "audiences": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "type": "string" }, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a private dns zone group." + "description": "The type for the federated identity credential." } }, "lockType": { @@ -30561,38 +25606,14 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "The type of a private DNS zone group configuration.", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } }, @@ -30667,7 +25688,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } @@ -30676,54 +25697,24 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the User Assigned Identity." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all resources." } }, - "applicationSecurityGroupResourceIds": { + "federatedIdentityCredentials": { "type": "array", "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "$ref": "#/definitions/federatedIdentityCredentialType" }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", "nullable": true, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." } }, "lock": { @@ -30747,39 +25738,9 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. Tags of the resource." }, "nullable": true }, @@ -30789,6 +25750,17 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } } }, "variables": { @@ -30801,23 +25773,20 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -30833,55 +25802,37 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" }, - "privateEndpoint_lock": { + "userAssignedIdentity_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "privateEndpoint" + "userAssignedIdentity" ] }, - "privateEndpoint_roleAssignments": { + "userAssignedIdentity_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "userAssignedIdentity_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -30892,14 +25843,19 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "userAssignedIdentity" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -30907,124 +25863,96 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" }, - "privateEndpointName": { + "userAssignedIdentityName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." } - } - }, - "parameters": { - "privateEndpointName": { + }, + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. The name of the secret." } }, - "privateDnsZoneConfigs": { + "audiences": { "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." } }, - "name": { + "issuer": { "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." } } }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" } } - }, + ], "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the federated identity credential." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the federated identity credential." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The name of the resource group the federated identity credential was created in." }, "value": "[resourceGroup().name]" } @@ -31032,235 +25960,300 @@ } }, "dependsOn": [ - "privateEndpoint" + "userAssignedIdentity" ] } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The name of the user assigned identity." }, "value": "[parameters('name')]" }, - "location": { + "resourceId": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The resource ID of the user assigned identity." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" }, - "groupId": { + "principalId": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The principal ID (object ID) of the user assigned identity." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_managementPolicies": { - "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "rules": { - "value": "[variables('formattedManagementPolicies')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4000605059554016072" - }, - "name": "Storage Account Management Policies", - "description": "This module deploys a Storage Account Management Policy." - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Required. The Storage Account ManagementPolicies Rules." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "value": "[reference('userAssignedIdentity').principalId]" }, - { - "type": "Microsoft.Storage/storageAccounts/managementPolicies", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", - "properties": { - "policy": { - "rules": "[parameters('rules')]" - } - } - } - ], - "outputs": { - "resourceId": { + "clientId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed management policy." + "description": "The client ID (application ID) of the user assigned identity." }, - "value": "default" + "value": "[reference('userAssignedIdentity').clientId]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the deployed management policy." + "description": "The resource group the user assigned identity was deployed into." }, - "value": "default" + "value": "[resourceGroup().name]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The resource group of the deployed management policy." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" } } } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the managed identity." }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "acrPullPrincipalIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').containerRegistry), 64)), '2025-04-01').outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8138805991948000285" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } }, - "storageAccount_localUsers": { - "copy": { - "name": "storageAccount_localUsers", - "count": "[length(coalesce(parameters('localUsers'), createArray()))]" + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user for the registry." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." + } + }, + "acrPullPrincipalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Principal IDs to assign AcrPull role." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable private networking." + } + }, + "privateEndpointSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for private endpoint." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Private DNS zone resource IDs for private endpoint." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Azure telemetry collection." + } + } + }, + "variables": { + "copy": [ + { + "name": "roleAssignments", + "count": "[length(parameters('acrPullPrincipalIds'))]", + "input": { + "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", + "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", + "principalType": "ServicePrincipal" + } }, + { + "name": "dnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" + } + } + ], + "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" + }, + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { + "name": { "value": "[parameters('name')]" }, - "name": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" + "location": { + "value": "[parameters('location')]" }, - "hasSshKey": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" + "tags": { + "value": "[parameters('tags')]" }, - "hasSshPassword": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "permissionScopes": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" + "acrSku": { + "value": "[parameters('sku')]" }, - "hasSharedKey": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" + "acrAdminUserEnabled": { + "value": "[parameters('adminUserEnabled')]" }, - "homeDirectory": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "sshAuthorizedKeys": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + "exportPolicyStatus": { + "value": "[parameters('exportPolicyStatus')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[variables('privateEndpointConfig')]" } }, "template": { @@ -31270,27 +26263,69 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1801226901235196767" + "version": "0.42.1.51946", + "templateHash": "1509121545318808417" }, - "name": "Storage Account Local Users", - "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR)." }, "definitions": { - "sshAuthorizedKeyType": { + "privateEndpointOutputType": { "type": "object", "properties": { - "description": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Description used to store the function/usage of the key." + "description": "The group Id for the private endpoint Group." } }, - "key": { - "type": "securestring", + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." } } }, @@ -31298,397 +26333,565 @@ "__bicep_export!": true } }, - "permissionScopeType": { + "credentialSetType": { "type": "object", "properties": { - "permissions": { + "name": { "type": "string", "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + "description": "Required. The name of the credential set." } }, - "resourceName": { - "type": "string", + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + "description": "Optional. The managed identity definition for this resource." } }, - "service": { + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { "type": "string", "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." + "description": "Required. The credentials are stored for this upstream or login server." } } }, "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The local user home directory." + "__bicep_export!": true, + "description": "The type for a credential set." } }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" + "scopeMapsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" + }, + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } }, "metadata": { - "description": "Required. The permission scopes of the local user." + "__bicep_export!": true, + "description": "The type for a scope map." } }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" + "cacheRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." + "__bicep_export!": true, + "description": "The type for a cache rule." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "replicationType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." } + }, + "zoneRedundancy": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" + }, + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + }, + "nullable": true } - } - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "localUsers": { - "type": "Microsoft.Storage/storageAccounts/localUsers", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "hasSharedKey": "[parameters('hasSharedKey')]", - "hasSshKey": "[parameters('hasSshKey')]", - "hasSshPassword": "[parameters('hasSshPassword')]", - "homeDirectory": "[parameters('homeDirectory')]", - "permissionScopes": "[parameters('permissionScopes')]", - "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed local user." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed local user." }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed local user." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_blobServices": { - "condition": "[not(empty(parameters('blobServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "containers": { - "value": "[tryGet(parameters('blobServices'), 'containers')]" - }, - "automaticSnapshotPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" - }, - "changeFeedEnabled": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" - }, - "changeFeedRetentionInDays": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" - }, - "containerDeleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" - }, - "containerDeleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" - }, - "corsRules": { - "value": "[tryGet(parameters('blobServices'), 'corsRules')]" - }, - "defaultServiceVersion": { - "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" - }, - "deleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" - }, - "deleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" - }, - "isVersioningEnabled": { - "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" - }, - "lastAccessTimeTrackingPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" - }, - "restorePolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" - }, - "restorePolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "468225492069709453" + "__bicep_export!": true, + "description": "The type for a replication." + } }, - "name": "Storage Account blob Services", - "description": "This module deploys a Storage Account Blob Service." - }, - "definitions": { - "corsRuleType": { + "taskType": { "type": "object", "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties for the task." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The step properties for the task." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The trigger properties for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the task at the time the operation was called." }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } + "nullable": true }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], + "timeout": { + "type": "int", + "nullable": true, "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." } }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The agent configuration for the task." }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." } }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, + "isSystemTask": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." + "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." } }, - "maxAgeInSeconds": { - "type": "int", + "logTemplate": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." + "description": "Optional. The log template for the task to use when creating logs in Log Analytics." } } }, "metadata": { "__bicep_export!": true, - "description": "The type for a cors rule." + "description": "The type for a task." } }, - "containerType": { + "tokenType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the Storage Container to deploy." + "description": "Required. The name of the token." } }, - "defaultEncryptionScope": { + "scopeMapResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." + "description": "Required. The resource ID of the scope map which defines the permissions for this token." } }, - "denyEncryptionScopeOverride": { - "type": "bool", + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" + }, + "description": "Optional. The status of the token at the time the operation was called." + }, + "nullable": true + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, "nullable": true, "metadata": { - "description": "Optional. Block override of encryption scope from the container default." + "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." } - }, - "enableNfsV3AllSquash": { - "type": "bool", + } + } + }, + "webhookType": { + "type": "object", + "properties": { + "name": { + "type": "string", "nullable": true, + "minLength": 5, + "maxLength": 50, "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." + "description": "Optional. The name of the registry webhook." } }, - "enableNfsV3RootSquash": { - "type": "bool", - "nullable": true, + "serviceUri": { + "type": "string", "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." + "description": "Required. The service URI for the webhook to post notifications." } }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the webhook at the time the operation was called." + }, + "nullable": true + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + "description": "Optional. The list of actions that trigger the webhook to post notifications." } }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", + "location": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Configure immutability policy." + "description": "Optional. Location for all resources." } }, - "metadata": { + "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" }, - "description": "Optional. A name-value pair to associate with the container as metadata." + "description": "Optional. Tags of the resource." }, "nullable": true }, - "publicAccess": { + "customHeaders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + }, + "description": "Optional. Custom headers that will be added to the webhook notifications." + }, + "nullable": true + }, + "scope": { "type": "string", - "allowedValues": [ - "Blob", - "Container", - "None" - ], "nullable": true, "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a webhook." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." } }, - "roleAssignments": { + "ipAddresses": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a storage container." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "description": "The type for auth credentials.", + "__bicep_imported_from!": { + "sourceTemplate": "credential-set/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, "diagnosticSettingFullType": { @@ -31756,92 +26959,288 @@ }, "nullable": true, "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "logAnalyticsDestinationType": { + "resourceGroupResourceId": { "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." } }, - "workspaceResourceId": { - "type": "string", + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." } }, - "storageAccountResourceId": { - "type": "string", + "isManualConnection": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. If Manual Private Link Connection is required." } }, - "eventHubAuthorizationRuleResourceId": { + "manualConnectionRequestMessage": { "type": "string", "nullable": true, + "maxLength": 140, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "eventHubName": { - "type": "string", + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Custom DNS configurations." } }, - "marketplacePartnerResourceId": { + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", + }, + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + "description": "Optional. Specify the type of lock." } }, - "allowProtectedAppendWrites": { - "type": "bool", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + "description": "Optional. Array of role assignments to create." } }, - "allowProtectedAppendWritesAll": { + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "description": "The type for an immutability policy.", + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", "__bicep_imported_from!": { - "sourceTemplate": "container/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, @@ -31916,220 +27315,515 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "storageAccountName": { + "name": { "type": "string", - "maxLength": 24, + "minLength": 5, + "maxLength": 50, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Required. Name of your Azure Container Registry." } }, - "automaticSnapshotPolicyEnabled": { + "acrAdminUserEnabled": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." + "description": "Optional. Enable admin user that have push / pull permission to the registry." } }, - "changeFeedEnabled": { - "type": "bool", - "defaultValue": false, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + "description": "Optional. Location for all resources." } }, - "changeFeedRetentionInDays": { - "type": "int", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, - "minValue": 1, - "maxValue": 146000, "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + "description": "Optional. Array of role assignments to create." + } + }, + "autoGeneratedDomainNameLabelScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse", + "Unsecure" + ], + "metadata": { + "description": "Optional. The domain name label reuse scope." } }, - "containerDeleteRetentionPolicyEnabled": { - "type": "bool", - "defaultValue": true, + "roleAssignmentMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AbacRepositoryPermissions", + "LegacyRegistryPermissions" + ], + "metadata": { + "description": "Optional. The registry permissions role assignment mode." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + "description": "Optional. The value that indicates whether the retention policy is enabled or not." } }, - "containerDeleteRetentionPolicyDays": { + "retentionPolicyDays": { "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." } }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { + "dataEndpointEnabled": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." } }, - "corsRules": { + "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/corsRuleType" + "$ref": "#/definitions/privateEndpointSingleServiceType" }, "nullable": true, "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." } }, - "defaultServiceVersion": { + "zoneRedundancy": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "items": { + "$ref": "#/definitions/replicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/webhookType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + "description": "Optional. The managed identity definition for this resource." } }, - "deleteRetentionPolicyEnabled": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. The blob service properties for blob soft delete." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "deleteRetentionPolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, - "maxValue": 365, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." + "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." } }, - "deleteRetentionPolicyAllowPermanentDelete": { + "anonymousPullEnabled": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." } }, - "isVersioningEnabled": { - "type": "bool", - "defaultValue": false, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + "description": "Optional. The customer managed key definition." } }, - "lastAccessTimeTrackingPolicyEnabled": { - "type": "bool", - "defaultValue": false, + "cacheRules": { + "type": "array", + "items": { + "$ref": "#/definitions/cacheRuleType" + }, + "nullable": true, "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + "description": "Optional. Array of Cache Rules." } }, - "restorePolicyEnabled": { - "type": "bool", - "defaultValue": false, + "credentialSets": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialSetType" + }, + "nullable": true, "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + "description": "Optional. Array of Credential Sets." } }, - "restorePolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, + "scopeMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/scopeMapsType" + }, + "nullable": true, "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + "description": "Optional. Scope maps setting." } }, - "containers": { + "tokens": { "type": "array", "items": { - "$ref": "#/definitions/containerType" + "$ref": "#/definitions/tokenType" }, "nullable": true, "metadata": { - "description": "Optional. Blob containers to create." + "description": "Optional. Tokens to create for the container registry." } }, - "diagnosticSettings": { + "tasks": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/taskType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of ACR Tasks to create." } } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], "enableReferencedModulesTelemetry": false, - "name": "default" + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", + "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", + "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", + "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" }, "resources": { - "storageAccount": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" }, - "blobServices": { - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", + "roleAssignmentMode": "[parameters('roleAssignmentMode')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "registry_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { - "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", - "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", - "containerDeleteRetentionPolicy": { - "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", - "days": "[parameters('containerDeleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" - }, - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "defaultServiceVersion": "[parameters('defaultServiceVersion')]", - "deleteRetentionPolicy": { - "enabled": "[parameters('deleteRetentionPolicyEnabled')]", - "days": "[parameters('deleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" - }, - "isVersioningEnabled": "[parameters('isVersioningEnabled')]", - "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", - "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "storageAccount" + "registry" ] }, - "blobServices_diagnosticSettings": { + "registry_diagnosticSettings": { "copy": { - "name": "blobServices_diagnosticSettings", + "name": "registry_diagnosticSettings", "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", "timeGrain": null } }, { "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" } } ], @@ -32141,58 +27835,56 @@ "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "blobServices" + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" ] }, - "blobServices_container": { + "registry_scopeMaps": { "copy": { - "name": "blobServices_container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "blobServiceName": { - "value": "[variables('name')]" - }, "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" - }, - "defaultEncryptionScope": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" - }, - "denyEncryptionScopeOverride": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" - }, - "enableNfsV3AllSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" - }, - "enableNfsV3RootSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" - }, - "immutableStorageWithVersioningEnabled": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" }, - "publicAccess": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" }, - "immutabilityPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + "registryName": { + "value": "[parameters('name')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -32205,202 +27897,40 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "273904034769611992" - }, - "name": "Storage Account Blob Containers", - "description": "This module deploys a Storage Account Blob Container." - }, - "definitions": { - "immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an immutability policy." - } + "version": "0.42.1.51946", + "templateHash": "3787322352564227867" }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } + "name": "Container Registries scope maps", + "description": "This module deploys an Azure Container Registry (ACR) scope map." }, "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "blobServiceName": { + "registryName": { "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." } }, "name": { "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + "description": "Optional. The name of the scope map." } }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", - "nullable": true, + "actions": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Optional. Configure immutability policy." + "description": "Required. The list of scoped permissions for registry artifacts." } }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. A name-value pair to associate with the container as metadata." - }, - "defaultValue": {} - }, - "publicAccess": { + "description": { "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Container", - "Blob", - "None" - ], + "nullable": true, "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + "description": "Optional. The user friendly description of the scope map." } }, "enableTelemetry": { @@ -32409,55 +27939,14 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, "resources": { - "storageAccount::blobServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" - }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -32473,813 +27962,820 @@ } } }, - "storageAccount": { + "registry": { "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" }, - "container": { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", "properties": { - "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", - "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", - "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", - "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", - "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", - "metadata": "[parameters('metadata')]", - "publicAccess": "[parameters('publicAccess')]" + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" }, - "container_roleAssignments": { - "copy": { - "name": "container_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." }, - "dependsOn": [ - "container" - ] + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6219097750044645017" }, - "container_immutabilityPolicy": { - "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "containerName": { - "value": "[parameters('name')]" - }, - "immutabilityPeriodSinceCreationInDays": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" - }, - "allowProtectedAppendWrites": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" - }, - "allowProtectedAppendWritesAll": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "15304742179563677019" - }, - "name": "Storage Account Blob Container Immutability Policies", - "description": "This module deploys a Storage Account Blob Container Immutability Policy." - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." - } - }, - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "defaultValue": 365, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", - "properties": { - "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", - "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", - "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" - } - } - ], + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed immutability policy." - }, - "value": "default" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed immutability policy." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed immutability policy." - }, - "value": "[resourceGroup().name]" + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } } - }, - "dependsOn": [ - "container" - ] + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed container." + "description": "The name of the replication." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed container." + "description": "The resource ID of the replication." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed container." + "description": "The name of the resource group the replication was created in." }, "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2025-11-01', 'full').location]" } } } }, "dependsOn": [ - "blobServices" + "registry" ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed blob service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - }, - "corsRules": { - "value": "[tryGet(parameters('fileServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17583198711200998285" - }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" + "registryName": { + "value": "[parameters('name')]" }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13412699468141336519" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a file share." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "definitions": { + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "__bicep_export!": true, + "description": "The type for auth credentials." + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } + "dependsOn": [ + "registry" + ] }, - "roleAssignmentType": { - "type": "object", + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1319901650921923538" + }, + "name": "Container Registry Cache", + "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "cacheRule": { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" - }, - "description": "Optional. Protocol settings for file service." - }, - "defaultValue": {} - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" - }, - "description": "Optional. The service properties for soft delete." - }, - "defaultValue": { - "enabled": true, - "days": 7 - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } + "dependsOn": [ + "registry", + "registry_credentialSets" + ] }, - "fileServices_diagnosticSettings": { + "registry_tokens": { "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "name": "registry_tokens", + "count": "[length(coalesce(parameters('tokens'), createArray()))]" }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "scopeMapResourceId": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5970335582661416899" + }, + "name": "Container Registries Tokens", + "description": "Deploys an Azure Container Registry (ACR) Token." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map to which the token will be associated with." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the token. Default is enabled." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + }, + "description": "Optional. The credentials associated with the token for authentication." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "token": { + "type": "Microsoft.ContainerRegistry/registries/tokens", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "scopeMapId": "[parameters('scopeMapResourceId')]", + "status": "[parameters('status')]", + "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the token." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the token was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the token." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "fileServices" + "registry", + "registry_scopeMaps" ] }, - "fileServices_shares": { + "registry_tasks": { "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" + "name": "registry_tasks", + "count": "[length(coalesce(parameters('tasks'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "registryName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" }, - "fileServicesName": { - "value": "[parameters('name')]" + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + "platform": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" + }, + "step": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" + }, + "trigger": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" + "status": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" + }, + "timeout": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + "agentConfiguration": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + "agentPoolName": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + "credentials": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" }, - "provisionedBandwidthMibps": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + "isSystemTask": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" }, - "provisionedIops": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + "logTemplate": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -33292,169 +28788,170 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "10353179772982843397" + "version": "0.42.1.51946", + "templateHash": "2468771835002458415" }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share." + "name": "Container Registries Tasks", + "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." }, "definitions": { - "roleAssignmentType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "storageAccountName": { + "registryName": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." } }, - "fileServicesName": { + "name": { "type": "string", - "defaultValue": "default", + "minLength": 5, + "maxLength": 50, "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + "description": "Required. The name of the task." } }, - "name": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The name of the file share to create." + "description": "Optional. Location for all resources." } }, - "accessTier": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties against which the task has to run." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The properties that describe all triggers for the task." + }, + "nullable": true + }, + "status": { "type": "string", - "nullable": true, + "defaultValue": "Enabled", "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" + "Disabled", + "Enabled" ], "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + "description": "Optional. The current status of task." } }, - "shareQuota": { + "timeout": { "type": "int", - "defaultValue": 5120, + "defaultValue": 3600, + "minValue": 300, + "maxValue": 28800, "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + "description": "Optional. Run timeout in seconds." } }, - "enabledProtocols": { + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The machine configuration of the run agent." + }, + "nullable": true + }, + "agentPoolName": { "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "nullable": true, "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Optional. The dedicated agent pool for the task." } }, - "rootSquash": { - "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" + }, + "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + }, + "nullable": true + }, + "isSystemTask": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + "description": "Optional. The value of this property indicates whether the task resource is system task or not." } }, - "provisionedBandwidthMibps": { - "type": "int", + "logTemplate": { + "type": "string", "nullable": true, - "minValue": 0, - "maxValue": 10340, "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + "description": "Optional. The template that describes the repository and tag information for run log artifact." } }, - "provisionedIops": { - "type": "int", + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, - "minValue": 0, - "maxValue": 102400, "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + "description": "Optional. The managed identity definition for this resource." } }, "enableTelemetry": { @@ -33463,53 +28960,18 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -33525,685 +28987,375 @@ } } }, - "storageAccount": { + "registry": { "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "task": { + "type": "Microsoft.ContainerRegistry/registries/tasks", + "apiVersion": "2025-03-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]", - "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", - "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + "agentConfiguration": "[parameters('agentConfiguration')]", + "agentPoolName": "[parameters('agentPoolName')]", + "credentials": "[parameters('credentials')]", + "isSystemTask": "[parameters('isSystemTask')]", + "logTemplate": "[parameters('logTemplate')]", + "platform": "[parameters('platform')]", + "status": "[parameters('status')]", + "step": "[parameters('step')]", + "timeout": "[parameters('timeout')]", + "trigger": "[parameters('trigger')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the task." }, - "dependsOn": [ - "storageAccount" - ] + "value": "[parameters('name')]" }, - "fileShare_roleAssignments": { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the task was deployed into." }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "scope": { - "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" - }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "condition": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" - }, - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string", - "metadata": { - "description": "Required. The scope to deploy the role assignment to." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[parameters('scope')]", - "name": "[parameters('name')]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "principalId": "[parameters('principalId')]", - "description": "[parameters('description')]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the task." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('task', '2025-03-01-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3200175097987099858" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "securestring", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } - ] + } } - }, - "dependsOn": [ - "fileShare" - ] + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + } } }, "outputs": { - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the deployed file share." + "description": "The resource ID of the webhook." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" }, - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share." + "description": "The name of the webhook." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "value": "[parameters('name')]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed file share." + "description": "The name of the Azure container registry." }, "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "fileServices", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_queueServices": { - "condition": "[not(empty(parameters('queueServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" - }, - "queues": { - "value": "[tryGet(parameters('queueServices'), 'queues')]" - }, - "corsRules": { - "value": "[tryGet(parameters('queueServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9644461291744477521" - }, - "name": "Storage Account Queue Services", - "description": "This module deploys a Storage Account Queue Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "queueType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the queue." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a queue." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "queues": { - "type": "array", - "items": { - "$ref": "#/definitions/queueType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Queues to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "queueServices": { - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" - } - }, - "queueServices_diagnosticSettings": { - "copy": { - "name": "queueServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2025-11-01', 'full').location]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "queueServices" + "registry" ] }, - "queueServices_queues": { + "registry_privateEndpoints": { "copy": { - "name": "queueServices_queues", - "count": "[length(coalesce(parameters('queues'), createArray()))]" + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, "name": { - "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -34214,12 +29366,98 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "12812824360066955039" + "templateHash": "18436885663402767850" }, - "name": "Storage Account Queues", - "description": "This module deploys a Storage Account Queue." + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." }, "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, "roleAssignmentType": { "type": "object", "properties": { @@ -34288,1211 +29526,1487 @@ } } }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] } }, - "parameters": { - "storageAccountName": { + "outputs": { + "resourceGroupName": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" }, "name": { "type": "string", "metadata": { - "description": "Required. The name of the storage queue to deploy." - } + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" }, - "metadata": { - "type": "object", + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true }, - "description": "Optional. A name-value pair that represents queue metadata." + "description": "The custom DNS configurations of the private endpoint." }, - "defaultValue": {} + "value": "[reference('privateEndpoint').customDnsConfigs]" }, - "roleAssignments": { + "networkInterfaceResourceIds": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "storageAccount::queueServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "queue": { - "type": "Microsoft.Storage/storageAccounts/queueServices/queues", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]" - } - }, - "queue_roleAssignments": { - "copy": { - "name": "queue_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "queue" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed queue." + "type": "string" }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed queue." + "description": "The resource IDs of the network interfaces associated with the private endpoint." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" }, - "resourceGroupName": { + "groupId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group of the deployed queue." + "description": "The group Id for the private endpoint Group." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } - } + }, + "dependsOn": [ + "registry", + "registry_replications" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed queue service." + "description": "The Name of the Azure container registry." }, - "value": "[variables('name')]" + "value": "[parameters('name')]" }, - "resourceId": { + "loginServer": { "type": "string", "metadata": { - "description": "The resource ID of the deployed queue service." + "description": "The reference to the Azure container registry." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + "value": "[reference('registry').loginServer]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed queue service." + "description": "The name of the Azure container registry." }, "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2025-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Azure container registry." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container registry." }, - "dependsOn": [ - "storageAccount" - ] + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The login server URL." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').containerRegistry), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('cae-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value)), createObject('value', null()))]", + "workloadProfiles": { + "value": [ + { + "name": "Consumption", + "workloadProfileType": "Consumption" + } + ] + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "platformReservedCidr": { + "value": "172.17.17.0/24" + }, + "platformReservedDnsIP": { + "value": "172.17.17.17" + }, + "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", + "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8036802024102680577" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app environment." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "managedIdentities": { + "type": "object", + "metadata": { + "description": "Managed identity configuration." + } + }, + "appLogsConfiguration": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Application logs configuration." + } + }, + "workloadProfiles": { + "type": "array", + "metadata": { + "description": "Workload profiles for the environment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + }, + "platformReservedCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Platform reserved CIDR block." + } + }, + "platformReservedDnsIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Platform reserved DNS IP." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether the environment is zone redundant." + } }, - "storageAccount_tableServices": { - "condition": "[not(empty(parameters('tableServices')))]", + "infrastructureSubnetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Infrastructure subnet resource ID." + } + } + }, + "resources": { + "containerAppEnvironment": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.app.managed-environment.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" - }, - "tables": { - "value": "[tryGet(parameters('tableServices'), 'tables')]" - }, - "corsRules": { - "value": "[tryGet(parameters('tableServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "10320403358700650147" - }, - "name": "Storage Account Table Services", - "description": "This module deploys a Storage Account Table Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "appLogsConfiguration": { + "value": "[parameters('appLogsConfiguration')]" + }, + "workloadProfiles": { + "value": "[parameters('workloadProfiles')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "platformReservedCidr": "[if(not(empty(parameters('platformReservedCidr'))), createObject('value', parameters('platformReservedCidr')), createObject('value', null()))]", + "platformReservedDnsIP": "[if(not(empty(parameters('platformReservedDnsIP'))), createObject('value', parameters('platformReservedDnsIP')), createObject('value', null()))]", + "zoneRedundant": { + "value": "[parameters('zoneRedundant')]" + }, + "infrastructureSubnetResourceId": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), createObject('value', parameters('infrastructureSubnetResourceId')), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11924518395502120940" }, - "diagnosticSettingFullType": { + "name": "App ManagedEnvironments", + "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." + }, + "definitions": { + "certificateType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Optional. The name of the certificate." } }, - "logAnalyticsDestinationType": { + "certificateType": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "ImagePullTrustedCA", + "ServerSSLCertificate" ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Optional. The type of the certificate." } }, - "workspaceResourceId": { + "certificateValue": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The value of the certificate. PFX or PEM blob." } }, - "storageAccountResourceId": { - "type": "string", + "certificatePassword": { + "type": "securestring", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The password of the certificate." } }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. A key vault reference." } }, - "eventHubName": { + "location": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The location for the resource." } }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, + "tags": { + "type": "object", "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "__bicep_export!": true, + "description": "The type for a certificate." } }, - "roleAssignmentType": { + "storageType": { "type": "object", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { + "accessMode": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "ReadOnly", + "ReadWrite" ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." } }, - "condition": { + "kind": { "type": "string", - "nullable": true, + "allowedValues": [ + "NFS", + "SMB" + ], "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." } }, - "conditionVersion": { + "storageAccountName": { "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Required. Storage account name." } }, - "delegatedManagedIdentityResourceId": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Required. File share name." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "tableServices": { - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + "__bicep_export!": true, + "description": "The type of the storage." } }, - "tableServices_diagnosticSettings": { - "copy": { - "name": "tableServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } + "appLogsConfigurationType": { + "type": "object", + "discriminator": { + "propertyName": "destination", + "mapping": { + "azure-monitor": { + "$ref": "#/definitions/appLogsConfigurationMonitorType" }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } + "log-analytics": { + "$ref": "#/definitions/appLogsConfigurationLawType" } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, - "dependsOn": [ - "tableServices" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type for the App Logs Configuration." + } }, - "tableServices_tables": { - "copy": { - "name": "tableServices_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "appLogsConfigurationMonitorType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "destination": { + "type": "string", + "allowedValues": [ + "azure-monitor" + ], "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "11362260974696477885" - }, - "name": "Storage Account Table", - "description": "This module deploys a Storage Account Table." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "storageAccount::tableServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "table": { - "type": "Microsoft.Storage/storageAccounts/tableServices/tables", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" - }, - "table_roleAssignments": { - "copy": { - "name": "table_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "table" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed table." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed table." - }, - "value": "[resourceGroup().name]" - } + "description": "Required. The destination of the logs." } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed table service." + } }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed table service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + "description": "The type for the App Logs Configuration if using azure-monitor." + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed table service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13227497656004178962" - } - }, - "definitions": { - "secretSetOutputType": { + "appLogsConfigurationLawType": { "type": "object", "properties": { - "secretResourceId": { + "destination": { "type": "string", + "allowedValues": [ + "log-analytics" + ], "metadata": { - "description": "The resourceId of the exported secret." + "description": "Required. The destination of the logs." } }, - "secretUri": { + "logAnalyticsWorkspaceResourceId": { "type": "string", "metadata": { - "description": "The secret URI of the exported secret." + "description": "Required. Existing Log Analytics Workspace resource ID." + } + } + }, + "metadata": { + "description": "The type for the App Logs Configuration if using log-analytics." + } + }, + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." } }, - "secretUriWithVersion": { + "keyVaultUrl": { "type": "string", "metadata": { - "description": "The secret URI with version of the exported secret." + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." } } }, "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "description": "The type for the certificate's key vault properties.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + "sourceTemplate": "certificate/main.bicep" } } }, - "secretToSetType": { + "lockType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the secret to set." + "description": "Optional. Specify the name of lock." } }, - "value": { - "type": "securestring", + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. The value of the secret to set." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "name": "[parameters('keyVaultName')]" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "managedIdentityAllType": { + "type": "object", "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_objectReplicationPolicies": { - "copy": { - "name": "storageAccount_objectReplicationPolicies", - "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "destinationAccountResourceId": { - "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" - }, - "enableMetrics": { - "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" - }, - "rules": { - "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1894366578172550759" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { + "roleAssignmentType": { "type": "object", "properties": { - "ruleId": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "containerName": { + "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the source container." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "destinationContainerName": { + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + "description": "Optional. The principal type of the assigned principal ID." } }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } - }, - "minCreationTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } - } - }, + "description": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The filters for the object replication policy rule." + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "The type of an object replication policy rule.", + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "policy/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } }, "parameters": { "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string." + } + }, + "daprConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" + }, + "description": "Optional. The configuration of Dapr component." + }, + "nullable": true + }, + "ingressConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" + }, + "description": "Optional. Ingress configuration for the Managed Environment." + }, + "nullable": true + }, + "kedaConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" + }, + "description": "Optional. The configuration of Keda component." + }, + "nullable": true + }, + "peerAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" + }, + "description": "Optional. Peer authentication settings for the Managed Environment." + }, + "nullable": true + }, + "daprAIConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." + } + }, + "daprAIInstrumentationKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." + } + }, + "dockerBridgeCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "infrastructureSubnetResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the policy." + "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "internal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." } }, - "storageAccountName": { + "platformReservedCidr": { "type": "string", - "maxLength": 24, + "defaultValue": "", "metadata": { - "description": "Required. The name of the parent Storage Account." + "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." } }, - "destinationAccountResourceId": { + "platformReservedDnsIP": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "peerTrafficEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not to encrypt peer traffic." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." + "description": "Optional. Whether to allow or block all public traffic." } }, - "enableMetrics": { + "zoneRedundant": { "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether or not this Managed Environment is zone-redundant." + } + }, + "certificatePassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Password of the certificate used by the custom domain." + } + }, + "certificateValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Certificate to use for the custom domain. PFX or PEM." + } + }, + "dnsSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. DNS suffix for the environment domain." + } + }, + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." + "description": "Optional. The lock settings of the service." + } + }, + "openTelemetryConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" + }, + "description": "Optional. Open Telemetry configuration." + }, + "nullable": true + }, + "workloadProfiles": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" + }, + "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." + }, + "nullable": true + }, + "infrastructureResourceGroupName": { + "type": "string", + "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", + "metadata": { + "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." } }, - "rules": { + "storages": { "type": "array", "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" + "$ref": "#/definitions/storageType" }, + "nullable": true, + "metadata": { + "description": "Optional. The list of storages to mount on the environment." + } + }, + "certificate": { + "$ref": "#/definitions/certificateType", + "nullable": true, + "metadata": { + "description": "Optional. A Managed Environment Certificate." + } + }, + "appLogsConfiguration": { + "$ref": "#/definitions/appLogsConfigurationType", + "nullable": true, "metadata": { - "description": "Required. Rules for the object replication policy." + "description": "Optional. The AppLogsConfiguration for the Managed Environment." } } }, "variables": { - "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", - "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", - "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", - "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, "resources": { - "storageAccount": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-11-01", + "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-02-01", + "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" + }, + "managedEnvironment": { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "appInsightsConfiguration": { + "connectionString": "[parameters('appInsightsConnectionString')]" + }, + "daprConfiguration": "[parameters('daprConfiguration')]", + "ingressConfiguration": "[parameters('ingressConfiguration')]", + "kedaConfiguration": "[parameters('kedaConfiguration')]", + "peerAuthentication": "[parameters('peerAuthentication')]", + "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", + "daprAIConnectionString": "[parameters('daprAIConnectionString')]", + "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", + "customDomainConfiguration": { + "certificatePassword": "[parameters('certificatePassword')]", + "certificateValue": "[parameters('certificateValue')]", + "dnsSuffix": "[parameters('dnsSuffix')]", + "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" + }, + "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", + "peerTrafficConfiguration": { + "encryption": { + "enabled": "[parameters('peerTrafficEncryption')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "vnetConfiguration": { + "internal": "[parameters('internal')]", + "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", + "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", + "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", + "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" + }, + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]", + "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "managedEnvironment_roleAssignments": { + "copy": { + "name": "managedEnvironment_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "managedEnvironment" + ] }, - "destinationPolicy": { + "managedEnvironment_storage": { + "copy": { + "name": "managedEnvironment_storage", + "count": "[length(coalesce(parameters('storages'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", - "subscriptionId": "[variables('destAccountSubscription')]", - "resourceGroup": "[variables('destAccountResourceGroupName')]", + "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -35500,22 +31014,19 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('name'), 'default')]" - }, - "storageAccountName": { - "value": "[variables('destAccountName')]" + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + "managedEnvironmentName": { + "value": "[parameters('name')]" }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" + "kind": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" + "accessMode": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" }, - "rules": { - "value": "[parameters('rules')]" + "storageAccountName": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" } }, "template": { @@ -35525,185 +31036,99 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14995722372031126283" + "version": "0.42.1.51946", + "templateHash": "945327737463253676" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } - }, - "minCreationTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy rule." - } - } + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the policy." + "description": "Required. The name of the file share." } }, - "storageAccountName": { + "managedEnvironmentName": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." } }, - "sourceStorageAccountResourceId": { + "accessMode": { "type": "string", "metadata": { - "description": "Required. Resource ID of the source storage account for replication." + "description": "Required. The access mode for the storage." } }, - "destinationAccountResourceId": { + "kind": { "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." } }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, + "storageAccountName": { + "type": "string", "metadata": { - "description": "Required. Rules for the object replication policy." + "description": "Required. Storage account name." } } }, "resources": { - "storageAccount": { + "managedEnvironment": { "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "storage": { + "type": "Microsoft.App/managedEnvironments/storages", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" - } - } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" - }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", + "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" } } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "Resource group name of the provisioned resources." + "description": "The name of the file share." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, - "objectReplicationPolicyId": { + "resourceId": { "type": "string", "metadata": { - "description": "Resource ID of the created Object Replication Policy." + "description": "The resource ID of the file share." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" }, - "policyId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Policy ID of the created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').policyId]" - }, - "rules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true - }, - "description": "Rules created Object Replication Policy." + "description": "The resource group the file share was deployed into." }, - "value": "[reference('objectReplicationPolicy').rules]" + "value": "[resourceGroup().name]" } } } - } + }, + "dependsOn": [ + "managedEnvironment" + ] }, - "sourcePolicy": { + "managedEnvironment_certificate": { + "condition": "[not(empty(parameters('certificate')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", + "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -35711,28 +31136,28 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[reference('destinationPolicy').outputs.policyId.value]" + "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "managedEnvironmentName": { + "value": "[parameters('name')]" }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + "certificateKeyVaultProperties": { + "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" + "certificateType": { + "value": "[tryGet(parameters('certificate'), 'certificateType')]" }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" + "certificateValue": { + "value": "[tryGet(parameters('certificate'), 'certificateValue')]" }, - "rules": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('rules'))]", - "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" - } - ] + "certificatePassword": { + "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" + }, + "location": { + "value": "[tryGet(parameters('certificate'), 'location')]" + }, + "tags": { + "value": "[tryGet(parameters('certificate'), 'tags')]" } }, "template": { @@ -35742,66 +31167,32 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14995722372031126283" + "version": "0.42.1.51946", + "templateHash": "574133184207535827" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." }, "definitions": { - "objectReplicationPolicyRuleType": { + "certificateKeyVaultPropertiesType": { "type": "object", "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { + "identityResourceId": { "type": "string", "metadata": { - "description": "Required. The name of the source container." + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." } }, - "destinationContainerName": { + "keyVaultUrl": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } - }, - "minCreationTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } - } - }, - "nullable": true, "metadata": { - "description": "Optional. The filters for the object replication policy rule." + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of an object replication policy rule." + "description": "The type for the certificate's key vault properties." } } }, @@ -35809,1468 +31200,2349 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." + "description": "Required. Name of the Container Apps Managed Environment Certificate." } }, - "sourceStorageAccountResourceId": { + "managedEnvironmentName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the source storage account for replication." + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." } }, - "destinationAccountResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." + "description": "Optional. Location for all Resources." } }, - "enableMetrics": { - "type": "bool", + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", "nullable": true, "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." + "description": "Optional. A key vault reference to the certificate to use for the custom domain." } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" - } - } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" - }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" - } - } - }, - "outputs": { - "resourceGroupName": { + "certificateType": { "type": "string", + "nullable": true, + "allowedValues": [ + "ServerSSLCertificate", + "ImagePullTrustedCA" + ], "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" + "description": "Optional. The type of the certificate." + } }, - "objectReplicationPolicyId": { + "certificateValue": { "type": "string", + "nullable": true, "metadata": { - "description": "Resource ID of the created Object Replication Policy." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + "description": "Optional. The value of the certificate. PFX or PEM blob." + } }, - "policyId": { - "type": "string", + "certificatePassword": { + "type": "securestring", + "nullable": true, "metadata": { - "description": "Policy ID of the created Object Replication Policy." - }, - "value": "[reference('objectReplicationPolicy').policyId]" + "description": "Optional. The password of the certificate." + } }, - "rules": { - "type": "array", + "tags": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" }, - "description": "Rules created Object Replication Policy." + "description": "Optional. Tags of the resource." }, - "value": "[reference('objectReplicationPolicy').rules]" + "nullable": true } - } - } - }, - "dependsOn": [ - "destinationPolicy" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.policyId.value]" - } - } - } - }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2025-06-01', 'full').location]" - }, - "serviceEndpoints": { - "type": "object", - "metadata": { - "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." - }, - "value": "[reference('storageAccount').primaryEndpoints]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the Storage Account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "primaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The primary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - }, - "secondaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The secondary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" - }, - "primaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" - }, - "secondaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", - "virtualNetwork" - ] - }, - "avmAiServices": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "projectName": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "projectDescription": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "existingFoundryProjectResourceId": { - "value": "[variables('existingProjectResourceId')]" - }, - "location": { - "value": "[parameters('azureAiServiceLocation')]" - }, - "sku": { - "value": "S0" - }, - "allowProjectManagement": { - "value": true - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "kind": { - "value": "AIServices" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('azureAiServiceLocation')]" - } - }, - "customSubDomainName": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" - } - }, - "disableLocalAuth": { - "value": true - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "deployments": { - "value": [ - { - "name": "[parameters('gptModelName')]", - "model": { - "format": "OpenAI", - "name": "[parameters('gptModelName')]", - "version": "[parameters('gptModelVersion')]" - }, - "sku": { - "name": "[parameters('deploymentType')]", - "capacity": "[parameters('gptDeploymentCapacity')]" - }, - "raiPolicyName": "Microsoft.Default" - } - ] - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "18336251851332975005" - }, - "name": "Cognitive Services", - "description": "This module deploys a Cognitive Service." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "managedEnvironmentCertificate": { + "type": "Microsoft.App/managedEnvironments/certificates", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", + "certificateType": "[parameters('certificateType')]", + "password": "[parameters('certificatePassword')]", + "value": "[parameters('certificateValue')]" + }, + "tags": "[parameters('tags')]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the certificate was deployed into." + }, + "value": "[resourceGroup().name]" + } + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } + "dependsOn": [ + "managedEnvironment" + ] } }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { + "outputs": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } + "description": "The name of the resource group the Managed Environment was deployed into." + }, + "value": "[resourceGroup().name]" }, - "format": { + "location": { "type": "string", "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } + "description": "The name of the Managed Environment." + }, + "value": "[parameters('name')]" }, - "size": { + "resourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } + "description": "The resource ID of the Managed Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" }, - "family": { + "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/project.bicep" - } - } - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "description": "The principal ID of the system assigned identity." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('managedEnvironment').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The IP address of the Managed Environment." + }, + "value": "[reference('managedEnvironment').staticIp]" + }, + "domainVerificationId": { + "type": "string", + "metadata": { + "description": "The domain verification id for custom domains." + }, + "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" + } } } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." }, + "value": "[reference('containerAppEnvironment').outputs.resourceId.value]" + }, + "name": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Name of the container app environment." + }, + "value": "[reference('containerAppEnvironment').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7070907820525585254" + } + }, + "parameters": { + "solutionSuffix": { + "type": "string", + "metadata": { + "description": "Unique solution suffix used to derive resource names." } }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + "location": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Azure region for the resource." } }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, + "environmentResourceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Resource ID of the container app environment." } }, - "privateEndpointSingleServiceType": { + "containerRegistryEndpoint": { + "type": "string", + "metadata": { + "description": "Container registry endpoint hosting the processor image." + } + }, + "imageTag": { + "type": "string", + "metadata": { + "description": "Image tag to deploy." + } + }, + "enableScalability": { + "type": "bool", + "metadata": { + "description": "Whether additional scale-out should be enabled." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether monitoring is enabled." + } + }, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string." + } + }, + "tags": { "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "User-assigned managed identity resource IDs to attach to the container app." + } + }, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. App Configuration endpoint for post-bootstrap updates." + } + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-app', parameters('solutionSuffix'))]", + "containerName": "[format('ca-{0}', parameters('solutionSuffix'))]", + "scaleSettings": "[if(empty(parameters('appConfigEndpoint')), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1)), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1), 'rules', if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-processor.{0}', parameters('solutionSuffix')), 64)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('containerAppName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "containers": { + "value": [ + { + "name": "[variables('containerName')]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } } }, - "parameters": { - "name": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account." - } + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "projectName": { + "name": { "type": "string", "metadata": { - "description": "Optional: Name for the project which needs to be created." - } + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" }, - "projectDescription": { + "fqdn": { "type": "string", "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "" + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "kind": { + "systemAssignedMIPrincipalId": { "type": "string", - "allowedValues": [ - "AIServices", - "AnomalyDetector", - "CognitiveServices", - "ComputerVision", - "ContentModerator", - "ContentSafety", - "ConversationalLanguageUnderstanding", - "CustomVision.Prediction", - "CustomVision.Training", - "Face", - "FormRecognizer", - "HealthInsights", - "ImmersiveReader", - "Internal.AllInOne", - "LUIS", - "LUIS.Authoring", - "LanguageAuthoring", - "MetricsAdvisor", - "OpenAI", - "Personalizer", - "QnAMaker.v2", - "SpeechServices", - "TextAnalytics", - "TextTranslation" - ], + "nullable": true, "metadata": { - "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "sku": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17990158768842819361" + } + }, + "parameters": { + "solutionSuffix": { "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Unique solution suffix used to derive resource names." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Azure region for the resource." } }, - "publicNetworkAccess": { + "environmentResourceId": { "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + "description": "Resource ID of the container app environment." } }, - "customSubDomainName": { + "containerRegistryEndpoint": { "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." - } - }, - "networkAcls": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A collection of rules governing the accessibility from specific network locations." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "allowedFqdnList": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of allowed FQDN." - } - }, - "apiProperties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The API properties for special APIs." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + "description": "Container registry endpoint hosting the API image." } }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "nullable": true, + "imageTag": { + "type": "string", "metadata": { - "description": "Optional. The customer managed key definition." + "description": "Image tag to deploy." } }, - "dynamicThrottlingEnabled": { + "enableScalability": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag to enable dynamic throttling." - } - }, - "migrationToken": { - "type": "securestring", - "nullable": true, "metadata": { - "description": "Optional. Resource migration token." + "description": "Whether additional scale-out should be enabled." } }, - "restore": { + "enableMonitoring": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." - } - }, - "restrictOutboundNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Restrict outbound network access." + "description": "Whether monitoring is enabled." } }, - "userOwnedStorage": { - "type": "array", - "nullable": true, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The storage accounts for this resource." + "description": "Optional. Application Insights connection string." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Tags to apply to the resource." } }, "enableTelemetry": { @@ -37280,173 +33552,184 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "deployments": { + "userAssignedResourceIds": { "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "allowProjectManagement": { - "type": "bool", - "nullable": true, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable project management feature for AI Foundry." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } } }, "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", - "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "containerAppName": "[format('ca-{0}-api', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" } } } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2025-01-31-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "cognitiveServiceNew": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]", - "kind": "[parameters('kind')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "properties": { - "allowProjectManagement": "[parameters('allowProjectManagement')]", - "customSubDomainName": "[parameters('customSubDomainName')]", - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", - "allowedFqdnList": "[parameters('allowedFqdnList')]", - "apiProperties": "[parameters('apiProperties')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", - "migrationToken": "[parameters('migrationToken')]", - "restore": "[parameters('restore')]", - "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", - "userOwnedStorage": "[parameters('userOwnedStorage')]", - "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" ] }, - "cognitiveServiceExisting": { - "condition": "[variables('useExistingService')]", - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", - "name": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "cognitive_service_dependencies": { - "condition": "[not(variables('useExistingService'))]", + "corsPolicy": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + }, + "resources": { + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", + "name": "[take(format('module.container-app-api.{0}', parameters('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, "name": { - "value": "[parameters('name')]" + "value": "[variables('containerAppName')]" }, "location": { "value": "[parameters('location')]" }, - "deployments": { - "value": "[parameters('deployments')]" + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" + "workloadProfileName": { + "value": "Consumption" }, - "lock": { - "value": "[parameters('lock')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" + "tags": { + "value": "[parameters('tags')]" }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] }, - "sku": { - "value": "[parameters('sku')]" + "scaleSettings": { + "value": "[variables('scaleSettings')]" }, - "tags": { - "value": "[parameters('tags')]" + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": "[variables('corsPolicy')]" } }, "template": { @@ -37457,1053 +33740,2197 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "8883353547455396972" + "templateHash": "11353975374580271835" } }, - "definitions": { - "privateEndpointOutputType": { + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" }, - "groupId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." + "description": "Optional. Array of role assignments to create." } }, - "format": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "version": { - "type": "string", + "customDomains": { + "type": "array", "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "ipSecurityRestrictions": { + "type": "array", "metadata": { - "description": "Required. The name of the resource model definition representing SKU." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." } }, - "capacity": { + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { "type": "int", "nullable": true, "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." + "description": "Optional. The termination grace period for the container app." } }, - "tier": { - "type": "string", + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, "nullable": true, "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." + "description": "Optional. The secrets of the Container App." } }, - "size": { + "revisionSuffix": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." + "description": "Optional. User friendly suffix that is appended to the revision name." } }, - "family": { + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "memberName": { + "fqdn": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "privateIPAddress": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + "description": "The name of the resource group the Container App was deployed into." }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + }, + "apiAppFqdn": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.fqdn.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9143297874990358007" + } + }, + "parameters": { + "solutionSuffix": { + "type": "string", + "metadata": { + "description": "Unique solution suffix used to derive resource names." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "containerRegistryEndpoint": { + "type": "string", + "metadata": { + "description": "Container registry endpoint hosting the web image." + } + }, + "imageTag": { + "type": "string", + "metadata": { + "description": "Image tag to deploy." + } + }, + "enableScalability": { + "type": "bool", + "metadata": { + "description": "Whether additional scale-out should be enabled." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "User-assigned managed identity resource IDs to attach to the container app." + } + }, + "apiAppFqdn": { + "type": "string", + "metadata": { + "description": "API application FQDN used by the frontend." + } + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-web', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + } + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-web.{0}', parameters('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "ingressExternal": { + "value": true + }, + "ingressTargetPort": { + "value": 3000 + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" + }, + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + "env": [ + { + "name": "APP_API_BASE_URL", + "value": "[format('https://{0}', parameters('apiAppFqdn'))]" }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + { + "name": "APP_WEB_CLIENT_ID", + "value": "" }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" + { + "name": "APP_WEB_AUTHORITY", + "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + { + "name": "APP_WEB_SCOPE", + "value": "" }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + { + "name": "APP_API_SCOPE", + "value": "" + }, + { + "name": "APP_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_POST_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_CONSOLE_LOG_ENABLED", + "value": "false" } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + ] } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account." + "description": "Name of the container app." } }, - "sku": { + "location": { "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Azure region for the resource." } }, - "location": { + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Resource ID of the container app environment." } }, - "tags": { + "managedIdentities": { "type": "object", - "nullable": true, + "defaultValue": {}, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Managed identity configuration." } }, - "deployments": { + "registries": { "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." + "description": "Optional. Container registry configuration." } }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, + "containers": { + "type": "array", "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Container definitions for the container app." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. Active revisions mode." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, + "scaleSettings": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Full scale settings object." } }, - "projectName": { - "type": "string", + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Optional: Name for the project which needs to be created." + "description": "Optional. Ingress target port." } }, - "projectDescription": { - "type": "string", + "ingressExternal": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional: Description for the project which needs to be created." + "description": "Whether ingress is external." } }, - "azureExistingAIProjectResourceId": { + "ingressTransport": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "Optional. Ingress transport setting." } - ], - "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" - }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." } }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." } }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." } }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -38511,43 +35938,43 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('name')]" }, "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "value": "[parameters('location')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "tags": { + "value": "[parameters('tags')]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -38556,823 +35983,776 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Container Apps", + "description": "This module deploys a Container App." }, "definitions": { - "privateDnsZoneGroupType": { + "ingressPortMappingType": { "type": "object", "properties": { - "name": { - "type": "string", + "exposedPort": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, + "external": { + "type": "bool", "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a private dns zone group." + "description": "The type for an ingress port mapping." } }, - "lockType": { + "serviceBindingType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Required. The name of the service." } }, - "notes": { + "serviceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Required. The service ID." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The type for a service binding." } }, - "privateDnsZoneGroupConfigType": { + "environmentVarType": { "type": "object", "properties": { "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." } }, - "privateDnsZoneResourceId": { + "value": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Non-secret environment variable value." } } }, "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } + "__bicep_export!": true, + "description": "The type for an environment variable." } }, - "roleAssignmentType": { + "containerAppProbeType": { "type": "object", "properties": { - "name": { - "type": "string", + "failureThreshold": { + "type": "int", "nullable": true, + "minValue": 1, + "maxValue": 10, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." } }, - "roleDefinitionIdOrName": { - "type": "string", + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. HTTPGet specifies the http request to perform." } }, - "principalId": { - "type": "string", + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." } }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], + "periodSeconds": { + "type": "int", "nullable": true, + "minValue": 1, + "maxValue": 240, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." } }, - "description": { - "type": "string", + "successThreshold": { + "type": "int", "nullable": true, + "minValue": 1, + "maxValue": 10, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." } }, - "condition": { - "type": "string", + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], + "terminationGracePeriodSeconds": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." } }, - "delegatedManagedIdentityResourceId": { + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The type of probe." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "The type for a container app probe." } }, - "tags": { + "corsPolicyType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } + "allowedMethods": { + "type": "array", + "items": { + "type": "string" }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." } } }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" + "__bicep_export!": true, + "description": "The type for a CORS policy." + } }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" + "description": "The type for a container app probe HTTP GET." + } }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } }, - "description": "The custom DNS configurations of the private endpoint." + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "metadata": { + "description": "The type for a container app probe TCP socket." + } }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } }, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "description": "The scale settings for the Container App." + } }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - } - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13560950051680758953" - } - }, - "definitions": { - "secretSetOutputType": { + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { "type": "object", "properties": { - "secretResourceId": { + "mountPath": { "type": "string", "metadata": { - "description": "The resourceId of the exported secret." + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." } }, - "secretUri": { + "subPath": { "type": "string", + "nullable": true, "metadata": { - "description": "The secret URI of the exported secret." + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." } }, - "secretUriWithVersion": { + "volumeName": { "type": "string", "metadata": { - "description": "The secret URI with version of the exported secret." + "description": "Required. This must match the Name of a Volume." } } }, "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "The type for a volume mount." } }, - "secretToSetType": { + "secretType": { "type": "object", "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the secret to set." + "description": "Optional. The name of the container app secret." } }, "value": { "type": "securestring", + "nullable": true, "metadata": { - "description": "Required. The value of the secret to set." + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." } } }, "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for a secret." } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." } }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, "metadata": { - "description": "Required. The secrets to set in the Key Vault." + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "lockType": { + "type": "object", "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - } - } - } - }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" - } - }, - "definitions": { - "aiProjectOutputType": { + }, + "roleAssignmentType": { "type": "object", "properties": { "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. Name of the AI project." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "resourceId": { + "principalId": { "type": "string", "metadata": { - "description": "Required. Resource ID of the AI project." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "apiEndpoint": { + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. API endpoint for the AI project." + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } } }, @@ -39380,1235 +36760,1215 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the AI Services project." + "description": "Required. Name of the Container App." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The location of the Project resource." + "description": "Optional. Location for all Resources." } }, - "desc": { + "kind": { "type": "string", - "defaultValue": "[parameters('name')]", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + "description": "Optional. Metadata used to render different experiences for resources of the same type." } }, - "aiServicesName": { + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + "description": "Optional. Client certificate mode for mTLS." } }, - "tags": { - "type": "object", - "defaultValue": {}, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, "metadata": { - "description": "Optional. Tags to be applied to the resources." + "description": "Optional. Object userd to configure CORS policy." } }, - "azureExistingAIProjectResourceId": { + "stickySessionsAffinity": { "type": "string", - "defaultValue": "", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + "description": "Optional. Bool indicating if the Container App should enable session affinity." } - } - }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." } - } - }, - "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", + }, + "service": { + "type": "object", "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." } - } - } - } - } - } - }, - "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" - } - } - } - }, - "dependsOn": [ - "cognitiveServiceNew" - ] - }, - "existing_cognitive_service_dependencies": { - "condition": "[variables('useExistingService')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('existingFoundryProjectResourceId')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "deployments": { - "value": "[parameters('deployments')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" - }, - "sku": { - "value": "[parameters('sku')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8883353547455396972" - } - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." + "description": "Optional. Settings to expose additional ports on container app." } }, - "format": { - "type": "string", + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." } }, - "version": { - "type": "string", + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." + "description": "Optional. Target Port in containers for traffic from ingress." } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, "metadata": { - "description": "Required. The name of the resource model definition representing SKU." + "description": "Optional. The scaling settings of the service." } }, - "capacity": { - "type": "int", + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, "nullable": true, "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." + "description": "Optional. List of container app services bound to the app." } }, - "tier": { + "activeRevisionsMode": { "type": "string", - "nullable": true, + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." + "description": "Optional. Controls how active revisions are handled for the Container app." } }, - "size": { + "environmentResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." + "description": "Required. Resource ID of environment." } }, - "family": { - "type": "string", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." + "description": "Optional. The lock settings of the service." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Array of role assignments to create." } }, - "memberName": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. User friendly suffix that is appended to the revision name." } }, - "privateIPAddress": { + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. Workload profile name to pin for container app execution." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } } - } + }, + "dependsOn": [ + "containerApp" + ] } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9387175626757048649" + } + }, + "parameters": { + "solutionSuffix": { + "type": "string", + "metadata": { + "description": "Unique solution suffix used to derive resource names." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "containerRegistryEndpoint": { + "type": "string", + "metadata": { + "description": "Container registry endpoint hosting the workflow image." + } + }, + "imageTag": { + "type": "string", + "metadata": { + "description": "Image tag to deploy." + } + }, + "enableScalability": { + "type": "bool", + "metadata": { + "description": "Whether additional scale-out should be enabled." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether monitoring is enabled." + } + }, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "User-assigned managed identity resource IDs to attach to the container app." + } + }, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. App Configuration endpoint for post-bootstrap updates." + } + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-wkfl', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-workflow.{0}', parameters('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + ] } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account." + "description": "Name of the container app." } }, - "sku": { + "location": { "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Azure region for the resource." } }, - "location": { + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Resource ID of the container app environment." } }, - "tags": { + "managedIdentities": { "type": "object", - "nullable": true, + "defaultValue": {}, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Managed identity configuration." } }, - "deployments": { + "registries": { "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." + "description": "Optional. Container registry configuration." } }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, + "containers": { + "type": "array", "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Container definitions for the container app." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. Active revisions mode." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, + "scaleSettings": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Full scale settings object." } }, - "projectName": { - "type": "string", + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Optional: Name for the project which needs to be created." + "description": "Optional. Ingress target port." } }, - "projectDescription": { - "type": "string", + "ingressExternal": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional: Description for the project which needs to be created." + "description": "Whether ingress is external." } }, - "azureExistingAIProjectResourceId": { + "ingressTransport": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "Optional. Ingress transport setting." } - ], - "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" - }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." } }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." } }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." } }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -40616,43 +37976,43 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('name')]" }, "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "value": "[parameters('location')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "tags": { + "value": "[parameters('tags')]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -40661,36 +38021,636 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { + "containerAppProbeHttpGetHeadersItemType": { "type": "object", "properties": { "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. Host name to connect to, defaults to the pod IP." } }, - "privateDnsZoneGroupConfigs": { + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/scaleRuleType" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a private dns zone group." + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, "lockType": { @@ -40726,31 +38686,35 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "privateDnsZoneGroupConfigType": { + "managedIdentityAllType": { "type": "object", "properties": { - "name": { - "type": "string", + "systemAssigned": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "privateDnsZoneResourceId": { - "type": "string", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "description": "The type of a private DNS zone group configuration.", + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -40825,7 +38789,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -40834,128 +38798,363 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Container App." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all Resources." } }, - "applicationSecurityGroupResourceIds": { + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/ingressPortMappingType" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. Settings to expose additional ports on container app." } }, - "customNetworkInterfaceName": { + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. The lock settings of the service." } }, - "ipConfigurations": { - "type": "array", + "tags": { + "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. Tags of the resource." }, "nullable": true }, - "ipVersionType": { - "type": "string", + "registries": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." }, - "defaultValue": "IPv4" + "nullable": true }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. The managed identity definition for this resource." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Array of role assignments to create." } }, - "lock": { - "$ref": "#/definitions/lockType", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. The termination grace period for the container app." } }, - "roleAssignments": { + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/secretType" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The secrets of the Container App." } }, - "tags": { - "type": "object", + "revisionSuffix": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true + "description": "Optional. User friendly suffix that is appended to the revision name." + } }, - "customDnsConfigs": { + "volumes": { "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" }, - "description": "Optional. Custom DNS configurations." + "description": "Optional. List of volume definitions for the Container App." }, "nullable": true }, - "manualPrivateLinkServiceConnections": { - "type": "array", + "workloadProfileName": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true + "description": "Optional. Workload profile name to pin for container app execution." + } }, - "privateLinkServiceConnections": { - "type": "array", + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true + "description": "Optional. The name of the Container App Auth configs." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The diagnostic settings of the service." } } }, @@ -40967,25 +39166,24 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -41001,567 +39199,345 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", "name": "[parameters('name')]", - "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - } - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13560950051680758953" - } - }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } - } - } - } - } - }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" } }, - "apiEndpoint": { - "type": "string", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. API endpoint for the AI project." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } + "dependsOn": [ + "containerApp" + ] } }, - "parameters": { - "name": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. Name of the AI Services project." - } + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" }, - "location": { + "fqdn": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The location of the Project resource." - } + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" }, - "desc": { + "resourceGroupName": { "type": "string", - "defaultValue": "[parameters('name')]", "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" }, - "aiServicesName": { + "name": { "type": "string", "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." - } + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" }, - "azureExistingAIProjectResourceId": { + "systemAssignedMIPrincipalId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" - } - } - }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" - }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" + "description": "The principal ID of the system assigned identity." }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" - } - } - }, - "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." + "description": "The location the resource was deployed into." }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } @@ -41569,607 +39545,227 @@ } }, "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, + "resourceId": { + "type": "string", "metadata": { - "description": "The private endpoints of the congitive services account." + "description": "Resource ID of the container app." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The service endpoint of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" - }, - "endpoints": { - "$ref": "#/definitions/endpointType", - "metadata": { - "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "logAnalyticsWorkspace" - ] - }, - "cognitiveServicePrivateEndpoint": { - "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "customNetworkInterfaceName": { - "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" - }, - "privateLinkServiceConnections": { - "value": [ - { - "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", - "properties": { - "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", - "groupIds": [ - "account" - ] - } - } - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDnsZoneGroupConfigs": [ - { - "name": "ai-services-dns-zone-cognitiveservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-openai", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-aiservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-contentunderstanding", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" - } - ] - } - }, - "subnetResourceId": { - "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } } } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, + "name": { + "type": "string", "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." }, + "value": "[reference('containerApp').outputs.fqdn.value]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-processor.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + }, + "appConfigEndpoint": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7070907820525585254" } }, "parameters": { - "name": { + "solutionSuffix": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Unique solution suffix used to derive resource names." } }, - "subnetResourceId": { + "location": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Azure region for the resource." } }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, + "environmentResourceId": { + "type": "string", "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Resource ID of the container app environment." } }, - "customNetworkInterfaceName": { + "containerRegistryEndpoint": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Container registry endpoint hosting the processor image." } }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { + "imageTag": { "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Image tag to deploy." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "enableScalability": { + "type": "bool", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Whether additional scale-out should be enabled." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Whether monitoring is enabled." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Application Insights connection string." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "manualPrivateLinkServiceConnections": { - "type": "array", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "privateLinkServiceConnections": { + "userAssignedResourceIds": { "type": "array", + "defaultValue": [], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true + "description": "User-assigned managed identity resource IDs to attach to the container app." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "containerAppName": "[format('ca-{0}-app', parameters('solutionSuffix'))]", + "containerName": "[format('ca-{0}', parameters('solutionSuffix'))]", + "scaleSettings": "[if(empty(parameters('appConfigEndpoint')), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1)), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1), 'rules', if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())))]" }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[take(format('module.container-app-processor.{0}', parameters('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -42177,13 +39773,82 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + "value": "[variables('containerAppName')]" }, - "privateEndpointName": { - "value": "[parameters('name')]" + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "containers": { + "value": [ + { + "name": "[variables('containerName')]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "scaleSettings": { + "value": "[variables('scaleSettings')]" } }, "template": { @@ -42193,966 +39858,1983 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" + } }, - "definitions": { - "privateDnsZoneGroupConfigType": { + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "privateDnsZoneResourceId": { - "type": "string", + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. The resource id of the private DNS zone." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } } } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." } } }, - "parameters": { - "privateEndpointName": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "description": "Resource ID of the container app." }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "Name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.name.value]" }, - "resourceId": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "Fully qualified domain name of the container app." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "resourceGroupName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[resourceGroup().name]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } - }, - "dependsOn": [ - "privateEndpoint" - ] + } } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "Resource ID of the container app." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "value": "[reference('containerApp').outputs.resourceId.value]" }, "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "Name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.name.value]" }, - "location": { + "fqdn": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "Fully qualified domain name of the container app." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "groupId": { + "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } }, "dependsOn": [ - "avmAiServices", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", - "virtualNetwork" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmContainerAppEnv": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('cae-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", - "workloadProfiles": { - "value": [ - { - "name": "Consumption", - "workloadProfileType": "Consumption" - } - ] - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "publicNetworkAccess": { - "value": "Enabled" - }, - "platformReservedCidr": { - "value": "172.17.17.0/24" - }, - "platformReservedDnsIP": { - "value": "172.17.17.17" - }, - "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", - "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "11924518395502120940" - }, - "name": "App ManagedEnvironments", - "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." - }, - "definitions": { - "certificateType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the certificate." - } - }, - "certificateType": { - "type": "string", - "allowedValues": [ - "ImagePullTrustedCA", - "ServerSSLCertificate" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the certificate." - } - }, - "certificateValue": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." - } - }, - "certificatePassword": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The password of the certificate." - } - }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", - "nullable": true, - "metadata": { - "description": "Optional. A key vault reference." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location for the resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a certificate." - } - }, - "storageType": { - "type": "object", - "properties": { - "accessMode": { - "type": "string", - "allowedValues": [ - "ReadOnly", - "ReadWrite" - ], - "metadata": { - "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Required. Storage account name." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. File share name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the storage." - } - }, - "appLogsConfigurationType": { - "type": "object", - "discriminator": { - "propertyName": "destination", - "mapping": { - "azure-monitor": { - "$ref": "#/definitions/appLogsConfigurationMonitorType" - }, - "log-analytics": { - "$ref": "#/definitions/appLogsConfigurationLawType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the App Logs Configuration." - } - }, - "appLogsConfigurationMonitorType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "azure-monitor" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using azure-monitor." - } - }, - "appLogsConfigurationLawType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "log-analytics" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - }, - "logAnalyticsWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Existing Log Analytics Workspace resource ID." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using log-analytics." - } - }, - "certificateKeyVaultPropertiesType": { - "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } - }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } - }, - "metadata": { - "description": "The type for the certificate's key vault properties.", - "__bicep_imported_from!": { - "sourceTemplate": "certificate/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container Apps Managed Environment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "appInsightsConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string." - } - }, - "daprConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" - }, - "description": "Optional. The configuration of Dapr component." - }, - "nullable": true - }, - "ingressConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" - }, - "description": "Optional. Ingress configuration for the Managed Environment." - }, - "nullable": true - }, - "kedaConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" - }, - "description": "Optional. The configuration of Keda component." - }, - "nullable": true - }, - "peerAuthentication": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" - }, - "description": "Optional. Peer authentication settings for the Managed Environment." - }, - "nullable": true - }, - "daprAIConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." - } - }, - "daprAIInstrumentationKey": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." - } - }, - "dockerBridgeCidr": { + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + }, + "appConfigEndpoint": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17990158768842819361" + } + }, + "parameters": { + "solutionSuffix": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Unique solution suffix used to derive resource names." } }, - "infrastructureSubnetResourceId": { + "location": { "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "internal": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Azure region for the resource." } }, - "platformReservedCidr": { + "environmentResourceId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Resource ID of the container app environment." } }, - "platformReservedDnsIP": { + "containerRegistryEndpoint": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "peerTrafficEncryption": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Whether or not to encrypt peer traffic." + "description": "Container registry endpoint hosting the API image." } }, - "publicNetworkAccess": { + "imageTag": { "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], "metadata": { - "description": "Optional. Whether to allow or block all public traffic." + "description": "Image tag to deploy." } }, - "zoneRedundant": { + "enableScalability": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not this Managed Environment is zone-redundant." - } - }, - "certificatePassword": { - "type": "securestring", - "defaultValue": "", "metadata": { - "description": "Optional. Password of the certificate used by the custom domain." + "description": "Whether additional scale-out should be enabled." } }, - "certificateValue": { - "type": "securestring", - "nullable": true, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Certificate to use for the custom domain. PFX or PEM." + "description": "Whether monitoring is enabled." } }, - "dnsSuffix": { + "appInsightsConnectionString": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. DNS suffix for the environment domain." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Application Insights connection string." } }, - "openTelemetryConfiguration": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" - }, - "description": "Optional. Open Telemetry configuration." - }, - "nullable": true - }, - "workloadProfiles": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" - }, - "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." - }, - "nullable": true - }, - "infrastructureResourceGroupName": { - "type": "string", - "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", - "metadata": { - "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Tags to apply to the resource." } }, - "storages": { - "type": "array", - "items": { - "$ref": "#/definitions/storageType" - }, - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The list of storages to mount on the environment." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "certificate": { - "$ref": "#/definitions/certificateType", - "nullable": true, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. A Managed Environment Certificate." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "appLogsConfiguration": { - "$ref": "#/definitions/appLogsConfigurationType", - "nullable": true, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The AppLogsConfiguration for the Managed Environment." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-11-01", - "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "containerAppName": "[format('ca-{0}-api', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" } } } - } - }, - "logAnalyticsWorkspace": { - "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", - "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" - }, - "managedEnvironment": { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "appInsightsConfiguration": { - "connectionString": "[parameters('appInsightsConnectionString')]" - }, - "daprConfiguration": "[parameters('daprConfiguration')]", - "ingressConfiguration": "[parameters('ingressConfiguration')]", - "kedaConfiguration": "[parameters('kedaConfiguration')]", - "peerAuthentication": "[parameters('peerAuthentication')]", - "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", - "daprAIConnectionString": "[parameters('daprAIConnectionString')]", - "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", - "customDomainConfiguration": { - "certificatePassword": "[parameters('certificatePassword')]", - "certificateValue": "[parameters('certificateValue')]", - "dnsSuffix": "[parameters('dnsSuffix')]", - "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" - }, - "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", - "peerTrafficConfiguration": { - "encryption": { - "enabled": "[parameters('peerTrafficEncryption')]" - } - }, - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "vnetConfiguration": { - "internal": "[parameters('internal')]", - "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", - "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", - "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", - "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" - }, - "workloadProfiles": "[parameters('workloadProfiles')]", - "zoneRedundant": "[parameters('zoneRedundant')]", - "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "managedEnvironment_roleAssignments": { - "copy": { - "name": "managedEnvironment_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "managedEnvironment" ] }, - "managedEnvironment_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "managedEnvironment" + "corsPolicy": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" ] - }, - "managedEnvironment_storage": { - "copy": { - "name": "managedEnvironment_storage", - "count": "[length(coalesce(parameters('storages'), createArray()))]" - }, + } + }, + "resources": { + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('module.container-app-api.{0}', parameters('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -43160,19 +41842,123 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" + "value": "[variables('containerAppName')]" }, - "managedEnvironmentName": { - "value": "[parameters('name')]" + "location": { + "value": "[parameters('location')]" }, - "kind": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" }, - "accessMode": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + "ingressTransport": { + "value": "auto" }, - "storageAccountName": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": "[variables('corsPolicy')]" } }, "template": { @@ -43183,3964 +41969,7373 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "945327737463253676" - }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." + "templateHash": "11353975374580271835" + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the file share." + "description": "Name of the container app." } }, - "managedEnvironmentName": { + "location": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "description": "Azure region for the resource." } }, - "accessMode": { - "type": "string", + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Required. The access mode for the storage." + "description": "Tags to apply to the resource." } }, - "kind": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "storageAccountName": { + "environmentResourceId": { "type": "string", "metadata": { - "description": "Required. Storage account name." + "description": "Resource ID of the container app environment." } - } - }, - "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" }, - "storage": { - "type": "Microsoft.App/managedEnvironments/storages", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", - "properties": { - "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", - "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." } - } - }, - "outputs": { - "name": { - "type": "string", + }, + "registries": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The name of the file share." - }, - "value": "[parameters('name')]" + "description": "Optional. Container registry configuration." + } }, - "resourceId": { - "type": "string", + "containers": { + "type": "array", "metadata": { - "description": "The resource ID of the file share." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" + "description": "Container definitions for the container app." + } }, - "resourceGroupName": { + "activeRevisionsMode": { "type": "string", + "defaultValue": "Single", "metadata": { - "description": "The resource group the file share was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_certificate": { - "condition": "[not(empty(parameters('certificate')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" - }, - "managedEnvironmentName": { - "value": "[parameters('name')]" - }, - "certificateKeyVaultProperties": { - "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" - }, - "certificateType": { - "value": "[tryGet(parameters('certificate'), 'certificateType')]" - }, - "certificateValue": { - "value": "[tryGet(parameters('certificate'), 'certificateValue')]" - }, - "certificatePassword": { - "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" - }, - "location": { - "value": "[tryGet(parameters('certificate'), 'location')]" - }, - "tags": { - "value": "[tryGet(parameters('certificate'), 'tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "574133184207535827" + "description": "Optional. Active revisions mode." + } }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." - }, - "definitions": { - "certificateKeyVaultPropertiesType": { + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } - }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } - }, + "defaultValue": {}, "metadata": { - "__bicep_export!": true, - "description": "The type for the certificate's key vault properties." + "description": "Optional. Full scale settings object." } - } - }, - "parameters": { - "name": { - "type": "string", + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Required. Name of the Container Apps Managed Environment Certificate." + "description": "Optional. Ingress target port." } }, - "managedEnvironmentName": { - "type": "string", + "ingressExternal": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "description": "Whether ingress is external." } }, - "location": { + "ingressTransport": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Ingress transport setting." } }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", - "nullable": true, + "secrets": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. A key vault reference to the certificate to use for the custom domain." + "description": "Optional. Secret definitions for the container app." } }, - "certificateType": { + "workloadProfileName": { "type": "string", - "nullable": true, - "allowedValues": [ - "ServerSSLCertificate", - "ImagePullTrustedCA" - ], + "defaultValue": "", "metadata": { - "description": "Optional. The type of the certificate." + "description": "Optional. Workload profile name." } }, - "certificateValue": { - "type": "string", - "nullable": true, + "disableIngress": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." + "description": "Optional. Whether ingress is disabled." } }, - "certificatePassword": { - "type": "securestring", - "nullable": true, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The password of the certificate." + "description": "Optional. Whether insecure ingress traffic is allowed." } }, - "tags": { + "corsPolicy": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true + "description": "Optional. CORS policy configuration." + } } }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" - }, - "managedEnvironmentCertificate": { - "type": "Microsoft.App/managedEnvironments/certificates", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", - "location": "[parameters('location')]", + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { - "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", - "certificateType": "[parameters('certificateType')]", - "password": "[parameters('certificatePassword')]", - "value": "[parameters('certificateValue')]" - }, - "tags": "[parameters('tags')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + } } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the key values." + "description": "Name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.name.value]" }, - "resourceId": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource ID of the key values." + "description": "Fully qualified domain name of the container app." }, - "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "resourceGroupName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group the certificate was deployed into." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[resourceGroup().name]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } - }, - "dependsOn": [ - "managedEnvironment" - ] + } } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Managed Environment was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { + "resourceId": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "Resource ID of the container app." }, - "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" + "value": "[reference('containerApp').outputs.resourceId.value]" }, "name": { "type": "string", "metadata": { - "description": "The name of the Managed Environment." + "description": "Name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.name.value]" }, - "resourceId": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource ID of the Managed Environment." + "description": "Fully qualified domain name of the container app." }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" - }, - "defaultDomain": { - "type": "string", - "metadata": { - "description": "The Default domain of the Managed Environment." - }, - "value": "[reference('managedEnvironment').defaultDomain]" - }, - "staticIp": { - "type": "string", - "metadata": { - "description": "The IP address of the Managed Environment." - }, - "value": "[reference('managedEnvironment').staticIp]" - }, - "domainVerificationId": { - "type": "string", - "metadata": { - "description": "The domain verification id for custom domains." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmContainerRegistryReader": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-workflow.update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" }, "location": { "value": "[parameters('location')]" }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." - }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "isolationScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], - "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" - }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" - }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" - }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "1387931959101373036" - }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." - }, - "parameters": { - "userAssignedIdentityName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "audiences": { - "type": "array", - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." - } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the federated identity credential." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the federated identity credential." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the federated identity credential was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "userAssignedIdentity" - ] - } + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - }, - "avmContainerApp": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" + "imageTag": { + "value": "[parameters('imageTag')]" }, - "location": { - "value": "[parameters('location')]" + "enableScalability": { + "value": "[parameters('enableScalability')]" }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" }, - "workloadProfileName": { - "value": "Consumption" + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "registries": { - "value": null - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { + "userAssignedResourceIds": { "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" ] }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, + "appConfigEndpoint": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9387175626757048649" + } + }, + "parameters": { + "solutionSuffix": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." + "description": "Unique solution suffix used to derive resource names." } }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, + "location": { + "type": "string", "metadata": { - "description": "The type for a service binding." + "description": "Azure region for the resource." } }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, + "environmentResourceId": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." + "description": "Resource ID of the container app environment." } }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, + "containerRegistryEndpoint": { + "type": "string", "metadata": { - "description": "The type for a container app probe." + "description": "Container registry endpoint hosting the workflow image." } }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, + "imageTag": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." + "description": "Image tag to deploy." } }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, + "enableScalability": { + "type": "bool", "metadata": { - "description": "The type for a container app probe HTTP GET." + "description": "Whether additional scale-out should be enabled." } }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The type for a container app probe HTTP GET header." + "description": "Whether monitoring is enabled." } }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "The type for a container app probe TCP socket." + "description": "Optional. Application Insights connection string." } }, - "scaleType": { + "tags": { "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "The scale settings for the Container App." + "description": "Tags to apply to the resource." } }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "The scaling rules for the Container App." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The type for a volume mount." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } - }, - "authConfigType": { - "type": "object", + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-wkfl', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-workflow.{0}', parameters('solutionSuffix')), 64)]", "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "expressionEvaluationOptions": { + "scope": "inner" }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressExternal": { + "value": false }, - "nullable": true + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" + } }, - "httpSettings": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + } + } }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." } - }, - "ipSecurityRestrictions": { - "type": "array", + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." + "description": "Resource ID of the container app." }, - "nullable": true + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "traffic": { - "type": "array", + "name": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + "description": "Name of the container app." }, - "nullable": true + "value": "[reference('containerApp').outputs.name.value]" }, - "dapr": { - "type": "object", + "fqdn": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." + "description": "Fully qualified domain name of the container app." }, - "nullable": true + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "identitySettings": { - "type": "array", + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + "description": "Principal ID of the system-assigned managed identity." }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "projectName": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "projectDescription": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "existingFoundryProjectResourceId": { + "value": "[variables('existingProjectResourceId')]" + }, + "location": { + "value": "[parameters('azureAiServiceLocation')]" + }, + "sku": { + "value": "S0" + }, + "allowProjectManagement": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "kind": { + "value": "AIServices" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('azureAiServiceLocation')]" + } + }, + "customSubDomainName": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value))), createObject('value', null()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "principalType": "ServicePrincipal" }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" } }, - "variables": { - "copy": [ + "disableLocalAuth": { + "value": true + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "deployments": { + "value": [ { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "name": "[parameters('gptModelName')]", + "model": { + "format": "OpenAI", + "name": "[parameters('gptModelName')]", + "version": "[parameters('gptModelVersion')]" + }, + "sku": { + "name": "[parameters('deploymentType')]", + "capacity": "[parameters('gptDeploymentCapacity')]" + }, + "raiPolicyName": "Microsoft.Default" } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + ] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "18161259334146424275" }, - "enableReferencedModulesTelemetry": false + "name": "Cognitive Services", + "description": "This module deploys a Cognitive Service." }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "definitions": { + "privateEndpointOutputType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } }, - "dependsOn": [ - "containerApp" - ] + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "deploymentType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { + "model": { + "type": "object", + "properties": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Required. The name of Cognitive Services account deployment model." } }, - "encryptionSettings": { - "type": "object", + "format": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Required. The format of Cognitive Services account deployment model." + } }, - "globalValidation": { - "type": "object", + "version": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Required. The name of the resource model definition representing SKU." + } }, - "identityProviders": { - "type": "object", + "capacity": { + "type": "int", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. The capacity of the resource model definition representing SKU." + } }, - "login": { - "type": "object", + "tier": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. The tier of the resource model definition representing SKU." + } }, - "platform": { - "type": "object", + "size": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. The size of the resource model definition representing SKU." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "family": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The family of the resource model definition representing SKU." } } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" }, - "outputs": { - "name": { + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceId": { + "memberName": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceGroupName": { + "privateIPAddress": { "type": "string", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." } } }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_API": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." } - ] - } - ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." } } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { + "_1.secretSetOutputType": { "type": "object", "properties": { - "exposedPort": { - "type": "int", - "nullable": true, + "secretResourceId": { + "type": "string", "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + "description": "The resourceId of the exported secret." } }, - "external": { - "type": "bool", + "secretUri": { + "type": "string", "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." + "description": "The secret URI of the exported secret." } }, - "targetPort": { - "type": "int", + "secretUriWithVersion": { + "type": "string", "metadata": { - "description": "Required. Specifies the port the container listens on." + "description": "The secret URI with version of the exported secret." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "serviceBindingType": { + "aiProjectOutputType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the service." + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." } }, - "serviceId": { + "apiEndpoint": { "type": "string", "metadata": { - "description": "Required. The service ID." + "description": "Required. API endpoint for the AI project." } } }, "metadata": { - "description": "The type for a service binding." + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/project.bicep" + } } }, - "environmentVarType": { + "customerManagedKeyType": { "type": "object", "properties": { - "name": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { "type": "string", "metadata": { - "description": "Required. Environment variable name." + "description": "Required. The name of the customer managed key to use for encryption." } }, - "secretRef": { + "keyVersion": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." } }, - "value": { + "userAssignedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Non-secret environment variable value." + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "containerAppProbeType": { + "diagnosticSettingFullType": { "type": "object", "properties": { - "failureThreshold": { - "type": "int", + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, "nullable": true, - "minValue": 1, - "maxValue": 10, "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, "nullable": true, "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." } }, - "initialDelaySeconds": { - "type": "int", + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], "nullable": true, - "minValue": 1, - "maxValue": 60, "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "periodSeconds": { - "type": "int", + "workspaceResourceId": { + "type": "string", "nullable": true, - "minValue": 1, - "maxValue": 240, "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "successThreshold": { - "type": "int", + "storageAccountResourceId": { + "type": "string", "nullable": true, - "minValue": 1, - "maxValue": 10, "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", + "eventHubAuthorizationRuleResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "terminationGracePeriodSeconds": { - "type": "int", + "eventHubName": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "timeoutSeconds": { - "type": "int", + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", "nullable": true, - "minValue": 1, - "maxValue": 240, "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + "description": "Optional. Specify the name of lock." } }, - "type": { + "kind": { "type": "string", "allowedValues": [ - "Liveness", - "Readiness", - "Startup" + "CanNotDelete", + "None", + "ReadOnly" ], "nullable": true, "metadata": { - "description": "Optional. The type of probe." + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "The type for a container app probe." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "corsPolicyType": { + "managedIdentityAllType": { "type": "object", "properties": { - "allowCredentials": { + "systemAssigned": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "allowedHeaders": { + "userAssignedResourceIds": { "type": "array", "items": { "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." } }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", "nullable": true, + "maxLength": 140, "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "allowedOrigins": { + "customDnsConfigs": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" }, "nullable": true, "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." + "description": "Optional. Custom DNS configurations." } }, - "exposeHeaders": { + "ipConfigurations": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" }, "nullable": true, "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." } }, - "maxAge": { - "type": "int", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { + }, + "customNetworkInterfaceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." } }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. HTTP headers to set in the request." + "description": "Optional. Specify the type of lock." } }, - "path": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { - "description": "Required. Path to access on the HTTP server." + "description": "Optional. Array of role assignments to create." } }, - "port": { - "type": "int", + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Required. Name or number of the port to access on the container." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." } }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], + "enableTelemetry": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "description": "The type for a container app probe HTTP GET." + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "containerAppProbeHttpGetHeadersItemType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the header." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "value": { + "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. Value of the header." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { + }, + "principalId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, "metadata": { - "description": "Required. The maximum number of replicas." + "description": "Optional. The principal type of the assigned principal ID." } }, - "minReplicas": { - "type": "int", + "description": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. The minimum number of replicas." + "description": "Optional. The description of the role assignment." } }, - "cooldownPeriod": { - "type": "int", + "condition": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The cooldown period in seconds." + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "pollingInterval": { - "type": "int", + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], "nullable": true, "metadata": { - "description": "Optional. The polling interval in seconds." + "description": "Optional. Version of the condition." } }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, + "delegatedManagedIdentityResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The scaling rules." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "The scale settings for the Container App." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "scaleRuleType": { + "secretsOutputType": { "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "" + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "processorPrincipalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Principal ID of the processor container app managed identity." + } + }, + "workflowPrincipalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Principal ID of the workflow container app managed identity." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, "metadata": { - "description": "The scaling rules for the Container App." + "description": "Optional. List of allowed FQDN." } }, - "volumeMountType": { + "apiProperties": { "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "gptModelName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. GPT model name used to build the default deployment." + } + }, + "gptModelVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. GPT model version used to build the default deployment." + } + }, + "gptDeploymentSkuName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Deployment SKU name for the default GPT deployment." + } + }, + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Deployment capacity for the default GPT deployment." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "allowProjectManagement": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable project management feature for AI Foundry." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "resolvedRoleAssignments": "[if(not(empty(coalesce(parameters('roleAssignments'), createArray()))), parameters('roleAssignments'), concat(if(not(empty(parameters('processorPrincipalId'))), createArray(createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services OpenAI User', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', 'Azure AI Developer', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services User', 'principalType', 'ServicePrincipal')), createArray()), if(not(empty(parameters('workflowPrincipalId'))), createArray(createObject('principalId', parameters('workflowPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services OpenAI User', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('workflowPrincipalId'), 'roleDefinitionIdOrName', 'Azure AI Developer', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('workflowPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services User', 'principalType', 'ServicePrincipal')), createArray())))]", + "resolvedDeployments": "[if(not(empty(coalesce(parameters('deployments'), createArray()))), parameters('deployments'), if(and(and(and(not(empty(parameters('gptModelName'))), not(empty(parameters('gptModelVersion')))), not(empty(parameters('gptDeploymentSkuName')))), greater(parameters('gptDeploymentCapacity'), 0)), createArray(createObject('name', parameters('gptModelName'), 'model', createObject('format', 'OpenAI', 'name', parameters('gptModelName'), 'version', parameters('gptModelVersion')), 'sku', createObject('name', parameters('gptDeploymentSkuName'), 'capacity', parameters('gptDeploymentCapacity')), 'raiPolicyName', 'Microsoft.Default')), createArray()))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", + "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } - }, - "metadata": { - "description": "The type for a volume mount." } }, - "secretType": { - "type": "object", + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2025-01-31-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "cognitiveServiceNew": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "allowProjectManagement": "[parameters('allowProjectManagement')]", + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "cognitiveServiceExisting": { + "condition": "[variables('useExistingService')]", + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[variables('existingCognitiveServiceDetails')[8]]" + }, + "cognitive_service_dependencies": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." + "mode": "Incremental", + "parameters": { + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[variables('resolvedDeployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[variables('resolvedRoleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "description": "An exported secret's references." } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + } + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + } + }, + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } } } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" + "cognitiveServiceNew" ] }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + "existing_cognitive_service_dependencies": { + "condition": "[variables('useExistingService')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[variables('existingCognitiveServiceDetails')[8]]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[variables('resolvedDeployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "lock": { + "value": "[parameters('lock')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "roleAssignments": { + "value": "[variables('resolvedRoleAssignments')]" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "sku": { + "value": "[parameters('sku')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -47151,3278 +49346,4693 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "8883353547455396972" + } }, - "parameters": { - "containerAppName": { - "type": "string", + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "encryptionSettings": { + "lockType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "nullable": true + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "globalValidation": { + "privateEndpointSingleServiceType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } }, - "nullable": true + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "httpSettings": { + "roleAssignmentType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } }, - "nullable": true + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "identityProviders": { + "secretsOutputType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } }, - "nullable": true + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } }, - "login": { - "type": "object", + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } }, - "platform": { + "tags": { "type": "object", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } - } - }, - "outputs": { - "name": { + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" + "description": "Optional: Name for the project which needs to be created." + } }, - "resourceId": { + "projectDescription": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "description": "Optional: Description for the project which needs to be created." + } }, - "resourceGroupName": { + "azureExistingAIProjectResourceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_Web": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "ingressExternal": { - "value": true - }, - "ingressTargetPort": { - "value": 3000 - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } } - } - } - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_API_BASE_URL", - "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" - }, - { - "name": "APP_WEB_CLIENT_ID", - "value": "" - }, - { - "name": "APP_WEB_AUTHORITY", - "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" - }, - { - "name": "APP_WEB_SCOPE", - "value": "" - }, - { - "name": "APP_API_SCOPE", - "value": "" - }, - { - "name": "APP_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_POST_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_CONSOLE_LOG_ENABLED", - "value": "false" - } - ] - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "enableReferencedModulesTelemetry": false }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } + } + } + } }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "outputs": { + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" } } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } }, - "parameters": { + "outputs": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } + "description": "The name of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" }, - "clientCertificateMode": { + "resourceId": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } + "description": "The resource ID of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" }, - "stickySessionsAffinity": { + "subscriptionId": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" }, - "ingressTransport": { + "resourceGroupName": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." + "description": "The resource group the cognitive services account was deployed into." }, - "nullable": true + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, + "endpoint": { + "type": "string", "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" + "description": "The service endpoint of the cognitive services account." }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, + "endpoints": { + "$ref": "#/definitions/endpointType", "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" }, - "environmentResourceId": { + "systemAssignedMIPrincipalId": { "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." + "description": "The principal ID of the system assigned identity." }, - "nullable": true + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" }, - "registries": { - "type": "array", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + "description": "The location the resource was deployed into." }, - "nullable": true + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" }, - "roleAssignments": { + "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/privateEndpointOutputType" }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." - } + "description": "The private endpoints of the congitive services account." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('srch-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "basic" + }, + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8530209533589901450" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "minLength": 3, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Solution name suffix used to derive the resource name." } }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, + "name": { + "type": "string", + "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." } }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "dapr": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "identitySettings": { - "type": "array", + "skuName": { + "type": "string", + "defaultValue": "basic", + "allowedValues": [ + "free", + "basic", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true + "description": "SKU name for the search service." + } }, - "maxInactiveRevisions": { + "replicaCount": { "type": "int", - "defaultValue": 0, + "defaultValue": 1, "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." + "description": "Number of replicas." } }, - "runtime": { - "type": "object", + "partitionCount": { + "type": "int", + "defaultValue": 1, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true + "description": "Number of partitions." + } }, - "containers": { - "type": "array", + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." + "description": "Hosting mode." } }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, + "semanticSearch": { + "type": "string", + "defaultValue": "free", + "allowedValues": [ + "disabled", + "free", + "standard" + ], "metadata": { - "description": "Optional. The termination grace period for the container app." + "description": "Semantic search tier." } }, - "initContainersTemplate": { - "type": "array", + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true + "description": "Whether to disable local authentication." + } }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, + "managedIdentityType": { + "type": "string", + "defaultValue": "SystemAssigned", "metadata": { - "description": "Optional. The secrets of the Container App." + "description": "Managed identity type for the search service." } }, - "revisionSuffix": { + "publicNetworkAccess": { "type": "string", - "nullable": true, + "defaultValue": "Enabled", "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "Public network access setting." } }, - "volumes": { - "type": "array", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "workloadProfileName": { - "type": "string", - "nullable": true, + "diagnosticSettings": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." + "description": "Diagnostic settings for monitoring." } }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, + "privateEndpoints": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. The name of the Container App Auth configs." + "description": "Private endpoint configurations." } }, - "diagnosticSettings": { + "roleAssignments": { "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create on the AI Search service." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "resources": { + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('skuName')]" } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "searchServiceUpdate": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('avm.res.search.update.{0}', parameters('name')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "sku": { + "value": "[parameters('skuName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": "[equals(parameters('managedIdentityType'), 'SystemAssigned')]" + } + }, + "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "6207719545398489494" + }, + "name": "Search Services", + "description": "This module deploys a Search Service." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the API Admin keys generated by the modules." + } + }, + "primaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAdminKey secret name to create." + } + }, + "secondaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAdminKey secret name to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." + } + }, + "authOptions": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/authOptions" + }, + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + }, + "nullable": true + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "computeType": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Confidential", + "Default" + ], + "metadata": { + "description": "Optional. The compute type of the search service." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "dataExfiltrationProtections": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Optional. A list of data exfiltration scenarios that are explicitly disallowed for the search service. Currently, the only supported value is 'All' to disable all possible data export scenarios with more fine grained controls planned for the future." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "HighDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings for all Resources in the solution." + } + }, + "networkRuleSet": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/networkRuleSet" + }, + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + }, + "nullable": true + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { + "publicNetworkAccess": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." } }, - "encryptionSettings": { - "type": "object", + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } }, - "globalValidation": { + "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "source": "Microsoft.Search/searchServices@2025-05-01#properties/tags" }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "description": "Optional. Tags to help categorize the resource in the Azure portal." }, "nullable": true + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', '')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "authOptions": "[parameters('authOptions')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]", + "computeType": "[parameters('computeType')]", + "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" + } + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } }, - "nullable": true + "dependsOn": [ + "searchService" + ] }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "2115224445601868607" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource." + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "nullable": true + "dependsOn": [ + "searchService" + ] }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "696453183181258843" } - } - } - } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp_API", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmContainerApp_Workflow": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[parameters('name')]" }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2025-05-01', 'full').location]" }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[reference('searchService').endpoint]" }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" } } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryKey": { + "type": "securestring", + "metadata": { + "description": "The primary admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" + }, + "secondaryKey": { + "type": "securestring", + "metadata": { + "description": "The secondaryKey admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } + "description": "Resource ID of the AI Search service." }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, + "name": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "System-assigned identity principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "minimumTlsVersion": { + "value": "TLS1_2" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", + "ipRules": [] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "supportsHttpsTrafficOnly": { + "value": true + }, + "accessTier": { + "value": "Hot" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageBlob), 64)), '2025-04-01').outputs.resourceId.value))), 'subnetResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageQueue), 64)), '2025-04-01').outputs.resourceId.value))), 'subnetResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "14745424667769468789" } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the Container App." + "description": "Name of the storage account." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." + "description": "Azure region for the resource." } }, - "ingressExternal": { + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, + "managedIdentities": { + "type": "object", "metadata": { - "description": "Optional. Object userd to configure CORS policy." + "description": "Managed identity configuration." } }, - "stickySessionsAffinity": { + "minimumTlsVersion": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], + "defaultValue": "TLS1_2", "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." + "description": "Minimum TLS version." } }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], + "roleAssignments": { + "type": "array", "metadata": { - "description": "Optional. Ingress transport protocol." + "description": "Role assignments for the storage account." } }, - "service": { + "networkAcls": { "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true + "description": "Network ACL configuration." + } }, - "includeAddOns": { + "requireInfrastructureEncryption": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." + "description": "Whether infrastructure encryption is required." } }, - "ingressAllowInsecure": { + "supportsHttpsTrafficOnly": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + "description": "Whether HTTPS traffic only is enforced." } }, - "environmentResourceId": { + "accessTier": { "type": "string", + "defaultValue": "Hot", "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Access tier for the storage account." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Tags to apply to the resource." } }, - "enableTelemetry": { + "allowBlobPublicAccess": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, + "defaultValue": false, "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "Whether blob public access is allowed." } }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { + "publicNetworkAccess": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, + "defaultValue": "Enabled", "metadata": { - "description": "Optional. The name of the Container App Auth configs." + "description": "Public network access setting." } }, - "diagnosticSettings": { + "privateEndpoints": { "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Private endpoint configuration." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + "storageAccount": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.storage.storage-account.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { + "name": { "value": "[parameters('name')]" }, + "location": { + "value": "[parameters('location')]" + }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "minimumTlsVersion": { + "value": "[parameters('minimumTlsVersion')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "networkAcls": { + "value": "[parameters('networkAcls')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "requireInfrastructureEncryption": { + "value": "[parameters('requireInfrastructureEncryption')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "supportsHttpsTrafficOnly": { + "value": "[parameters('supportsHttpsTrafficOnly')]" }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "accessTier": { + "value": "[parameters('accessTier')]" + }, + "tags": { + "value": "[parameters('tags')]" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "allowBlobPublicAccess": { + "value": "[parameters('allowBlobPublicAccess')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" } }, "template": { @@ -50432,5063 +54042,3307 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" + "version": "0.41.2.15936", + "templateHash": "1254456195180100771" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "name": "Storage Accounts", + "description": "This module deploys a Storage Account." }, - "parameters": { - "containerAppName": { - "type": "string", + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoints output." + } + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network configuration." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey1 secret name to create." + } + }, + "connectionString1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString1 secret name to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey2 secret name to create." + } + }, + "connectionString2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString2 secret name to create." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type of the exported secrets." } }, - "encryptionSettings": { + "localUserType": { "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "__bicep_export!": true, + "description": "The type of a local user." + } + }, + "blobServiceType": { + "type": "object", + "properties": { + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/blobCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "versionDeletePolicyDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "__bicep_export!": true, + "description": "The type of a blob service." } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + }, + "fileServiceType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." + }, + "nullable": true + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "nullable": true + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/fileCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." } } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a file service." } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "queueServiceType": { + "type": "object", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/queueCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } }, - "value": "current" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "__bicep_export!": true, + "description": "The type of a queue service." + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" - ] - }, - "avmCosmosDB": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "mongodbDatabases": { - "value": [ - { - "name": "default", - "tag": "default database" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "databaseAccountOfferType": { - "value": "Standard" - }, - "enableAutomaticFailover": { - "value": false - }, - "serverVersion": { - "value": "7.0" - }, - "capabilitiesToAdd": { - "value": [ - "EnableMongo" - ] - }, - "defaultConsistencyLevel": { - "value": "Session" - }, - "maxIntervalInSeconds": { - "value": 5 - }, - "maxStalenessPrefix": { - "value": 100 - }, - "zoneRedundant": { - "value": false - }, - "networkRestrictions": { - "value": { - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", - "ipRules": [], - "virtualNetworkRules": [] - } - }, - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1772014800591596213" - }, - "name": "Azure Cosmos DB account", - "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group ID for the private endpoint group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "tableServiceType": { + "type": "object", + "properties": { + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } }, - "metadata": { - "description": "A list of private IP addresses for the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "failoverLocationType": { - "type": "object", - "properties": { - "failoverPriority": { - "type": "int", - "metadata": { - "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." - } - }, - "isZoneRedundant": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." - } - }, - "locationName": { - "type": "string", - "metadata": { - "description": "Required. The name of the region." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the failover location." - } - }, - "sqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." - } - }, - "sqlRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of data actions that are allowed." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." - } - }, - "assignments": { - "type": "array", - "items": { - "$ref": "#/definitions/nestedSqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." - } - }, - "networkRestrictionType": { - "type": "object", - "properties": { - "ipRules": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." - } - }, - "networkAclBypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." - } - }, - "publicNetworkAccess": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." - } - }, - "virtualNetworkRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of a subnet." + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/tableCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a table service." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." - } - }, - "networkAclBypassResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network restriction." - } - }, - "gremlinDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin database resource." - }, - "nullable": true - }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a gremlin databae." - } - }, - "mongoDbType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "items": { - "$ref": "#/definitions/collectionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "autoscaleSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." - }, - "nullable": true - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + "objectReplicationPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." + } + }, + "destinationStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the destination storage account." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. The storage account object replication rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy." + } }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a mongo databae." - } - }, - "sqlDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + "_1.immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/container/main.bicep" + } + } }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a sql database." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + "_2.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } - }, - "cassandraStandaloneRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." - } - }, - "cassandraRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." - } - }, - "notDataActions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." - } - }, - "assignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." - } - }, - "cassandraKeyspaceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra keyspace." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraTableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." - } - }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraViewType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + "_2.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Optional. Tags of the Cassandra keyspace resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB Cassandra keyspace." - } - }, - "defaultIdentityType": { - "type": "object", - "discriminator": { - "propertyName": "name", - "mapping": { - "FirstPartyIdentity": { - "$ref": "#/definitions/defaultIdentityFirstPartyType" - }, - "SystemAssignedIdentity": { - "$ref": "#/definitions/defaultIdentitySystemAssignedType" - }, - "UserAssignedIdentity": { - "$ref": "#/definitions/defaultIdentityUserAssignedType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the default identity." - } - }, - "defaultIdentityFirstPartyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "FirstPartyIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - } - } - }, - "defaultIdentitySystemAssignedType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "SystemAssignedIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - } - } - }, - "defaultIdentityUserAssignedType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "UserAssignedIdentity" - ], - "metadata": { - "description": "Required. The type of default identity to use." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the user assigned identity to use as the default identity." - } - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + "_2.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "memberName": { - "type": "string", + "_2.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + "blobCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep", + "originalIdentifier": "corsRuleType" } } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "cassandraRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-role-definition/main.bicep" - } - } - }, - "cassandraTableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "schema": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Analytical TTL for the table." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." - } - } - }, - "metadata": { - "description": "The type of a Cassandra table.", - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "tableType" - } - } - }, - "cassandraViewType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the view." - } - }, - "viewDefinition": { - "type": "string", - "metadata": { - "description": "Required. View definition (CQL statement)." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags for the view." - }, - "nullable": true - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." - } - } - }, - "metadata": { - "description": "The type of a Cassandra view (materialized view).", - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "viewType" - } - } - }, - "collectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, - "metadata": { - "description": "The type of a collection.", - "__bicep_imported_from!": { - "sourceTemplate": "mongodb-database/main.bicep" - } - } - }, - "containerType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" - }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - }, - "nullable": true - }, - "kind": { - "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - } - }, - "metadata": { - "description": "The type of a container.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-database/main.bicep" - } - } - }, - "customerManagedKeyAndVaultOnlyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/_1.immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "The type of a storage container.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "graphType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true - } - }, - "metadata": { - "description": "The type of a graph.", - "__bicep_imported_from!": { - "sourceTemplate": "gremlin-database/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "nestedSqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "description": "The type for the SQL Role Assignments.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-role-definition/main.bicep", - "originalIdentifier": "sqlRoleAssignmentType" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the account." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Defaults to the current resource group scope location. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the resource." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "databaseAccountOfferType": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard" - ], - "metadata": { - "description": "Optional. The offer type for the account. Defaults to \"Standard\"." - } - }, - "failoverLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/failoverLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." - } - }, - "defaultConsistencyLevel": { - "type": "string", - "defaultValue": "Session", - "allowedValues": [ - "Eventual", - "ConsistentPrefix", - "Session", - "BoundedStaleness", - "Strong" - ], - "metadata": { - "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." - } - }, - "disableLocalAuthentication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." - } - }, - "enableAnalyticalStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." - } - }, - "enableAutomaticFailover": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable automatic failover for regions. Defaults to true." - } - }, - "enableFreeTier": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." - } - }, - "enableMultipleWriteLocations": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." - } - }, - "disableKeyBasedMetadataWriteAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." - } - }, - "maxStalenessPrefix": { - "type": "int", - "defaultValue": 100000, - "minValue": 1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." - } - }, - "maxIntervalInSeconds": { - "type": "int", - "defaultValue": 300, - "minValue": 5, - "maxValue": 86400, - "metadata": { - "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." - } - }, - "serverVersion": { - "type": "string", - "defaultValue": "4.2", - "allowedValues": [ - "3.2", - "3.6", - "4.0", - "4.2", - "5.0", - "6.0", - "7.0" - ], - "metadata": { - "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." - } - }, - "sqlDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlDatabaseType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." - } - }, - "mongodbDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/mongoDbType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." - } - }, - "gremlinDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/gremlinDatabaseType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." - } - }, - "cassandraKeyspaces": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraKeyspaceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "totalThroughputLimit": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of control plane Azure role-based access control assignments." - } - }, - "sqlRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleDefinitionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." - } - }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." - } - }, - "cassandraRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleDefinitionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." - } - }, - "cassandraRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings for the service." - } - }, - "capabilitiesToAdd": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "allowedValues": [ - "EnableCassandra", - "EnableTable", - "EnableGremlin", - "EnableMongo", - "DisableRateLimitingResponses", - "EnableServerless", - "EnableNoSQLVectorSearch", - "EnableNoSQLFullTextSearch", - "EnableMaterializedViews", - "DeleteAllItemsByPartitionKey" - ], - "metadata": { - "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." - } - }, - "backupPolicyType": { - "type": "string", - "defaultValue": "Continuous", - "allowedValues": [ - "Periodic", - "Continuous" - ], - "metadata": { - "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." - } - }, - "backupPolicyContinuousTier": { - "type": "string", - "defaultValue": "Continuous30Days", - "allowedValues": [ - "Continuous30Days", - "Continuous7Days" - ], - "metadata": { - "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." - } - }, - "backupIntervalInMinutes": { - "type": "int", - "defaultValue": 240, - "minValue": 60, - "maxValue": 1440, - "metadata": { - "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." - } - }, - "backupRetentionIntervalInHours": { - "type": "int", - "defaultValue": 8, - "minValue": 2, - "maxValue": 720, - "metadata": { - "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." - } - }, - "backupStorageRedundancy": { - "type": "string", - "defaultValue": "Local", - "allowedValues": [ - "Geo", - "Local", - "Zone" - ], - "metadata": { - "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." - } - }, - "networkRestrictions": { - "$ref": "#/definitions/networkRestrictionType", - "defaultValue": { - "ipRules": [], - "virtualNetworkRules": [], - "publicNetworkAccess": "Disabled" - }, - "metadata": { - "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "Tls12", - "allowedValues": [ - "Tls12" - ], - "metadata": { - "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." - } - }, - "enableBurstCapacity": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." - } - }, - "enableCassandraConnector": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." - } - }, - "enablePartitionMerge": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." - } - }, - "enablePerRegionPerPartitionAutoscale": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." - } - }, - "analyticalStorageConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" - }, - "description": "Optional. Analytical storage specific properties." - }, - "nullable": true - }, - "cors": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" - }, - "description": "Optional. The CORS policy for the Cosmos DB database account." - }, - "nullable": true - }, - "defaultIdentity": { - "$ref": "#/definitions/defaultIdentityType", - "defaultValue": { - "name": "FirstPartyIdentity" - }, - "metadata": { - "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInControlPlaneRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", - "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", - "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", - "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", - "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" - }, - "databaseAccount": { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", - "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", - "dependsOn": [ - "cMKKeyVault::cMKKey" - ] - }, - "databaseAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_diagnosticSettings": { - "copy": { - "name": "databaseAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_roleAssignments": { - "copy": { - "name": "databaseAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlDatabases": { - "copy": { - "name": "databaseAccount_sqlDatabases", - "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" - }, - "containers": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" - }, - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "3972888645334640168" + "fileCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } }, - "name": "DocumentDB Database Account SQL Databases", - "description": "This module deploys a SQL Database in a CosmosDB Account." - }, - "definitions": { - "containerType": { + "fileShareType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the container." + "description": "Required. The name of the file share." } }, - "analyticalStorageTtl": { - "type": "int", + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], "nullable": true, "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." } }, - "conflictResolutionPolicy": { - "type": "object", + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" - }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } }, - "defaultTtl": { - "type": "int", + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], "nullable": true, - "minValue": -1, - "maxValue": 2147483647, "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." } }, - "throughput": { + "shareQuota": { "type": "int", "nullable": true, "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." } }, - "autoscaleSettingsMaxThroughput": { + "provisionedBandwidthMibps": { "type": "int", "nullable": true, - "maxValue": 1000000, + "maxValue": 10340, "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." } }, - "tags": { - "type": "object", + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } }, - "paths": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, - "maxLength": 3, + "nullable": true, "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + "description": "Optional. Array of role assignments to create." } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", + } + }, + "metadata": { + "description": "The type for a file share.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" - }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - }, - "nullable": true + "description": "Optional. Specify the name of lock." + } }, "kind": { "type": "string", "allowedValues": [ - "Hash", - "MultiHash" + "CanNotDelete", + "None", + "ReadOnly" ], "nullable": true, "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + "description": "Optional. Specify the type of lock." } }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], + "notes": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a container." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "tags": { + "managedIdentityAllType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", "properties": { - "resource": { - "id": "[parameters('name')]" + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "dependsOn": [ - "databaseAccount" - ] + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "container": { - "copy": { - "name": "container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "objectReplicationPolicyRuleType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "sqlDatabaseName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" - }, - "analyticalStorageTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "conflictResolutionPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" - }, - "defaultTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" - }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" - }, - "kind": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" - }, - "version": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" - }, - "paths": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" - }, - "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", - "uniqueKeyPolicyKeys": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "destinationContainerName": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "4781880351108045502" - }, - "name": "DocumentDB Database Account SQL Database Containers", - "description": "This module deploys a SQL Database Container in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "sqlDatabaseName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" - }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { "type": "array", "items": { "type": "string" }, - "minLength": 1, - "maxLength": 3, + "nullable": true, "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + "description": "Optional. The prefix to match for the replication policy rule." } }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" - }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - }, - "nullable": true - }, - "kind": { + "minCreationTime": { "type": "string", - "defaultValue": "Hash", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "defaultValue": 1, - "allowedValues": [ - 1, - 2 - ], + "nullable": true, "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - } - }, - "variables": { - "copy": [ - { - "name": "partitionKeyPaths", - "count": "[length(parameters('paths'))]", - "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + "description": "Optional. The minimum creation time to match for the replication policy rule." } - ] - }, - "resources": { - "databaseAccount::sqlDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "container": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, - "dependsOn": [ - "databaseAccount" - ] } }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the container was created in." - }, - "value": "[resourceGroup().name]" - } + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." } } }, - "dependsOn": [ - "sqlDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlRoleDefinitions": { - "copy": { - "name": "databaseAccount_sqlRoleDefinitions", - "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "dataActions": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" - }, - "roleName": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "sqlRoleAssignments": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "8514367433037227852" + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "object-replication-policy/policy/main.bicep" + } + } }, - "name": "DocumentDB Database Account SQL Role Definitions.", - "description": "This module deploys a SQL Role Definision in a CosmosDB Account." - }, - "definitions": { - "sqlRoleAssignmentType": { + "permissionScopeType": { "type": "object", "properties": { - "name": { + "permissions": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." } }, - "principalId": { + "resourceName": { "type": "string", "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." } }, - "scope": { + "service": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + "description": "Required. The service used by the local user, e.g. blob, file." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for the SQL Role Assignments." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the Role Definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of data actions that are allowed." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." - } - }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" } } }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "privateEndpointMultiServiceType": { + "type": "object", "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ - { - "dataActions": "[parameters('dataActions')]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." } - ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" - } - }, - "databaseAccount_sqlRoleAssignments": { - "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "roleDefinitionIdOrName": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" - } - } + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "dependsOn": [ - "sqlRoleDefinition" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL Role Definition." - }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL Role Definition." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." - }, - "value": "[resourceGroup().name]" - }, - "roleName": { - "type": "string", - "metadata": { - "description": "The role name of the SQL Role Definition." - }, - "value": "[reference('sqlRoleDefinition').roleName]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlRoleAssignments": { - "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "roleDefinitionIdOrName": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "principalId": { - "type": "string", + "queueCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep", + "originalIdentifier": "corsRuleType" + } } }, - "roleDefinitionIdOrName": { - "type": "string", + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." + "description": "The type for a queue.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep" + } } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "scope": { - "type": "string", - "nullable": true, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_2.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - } - }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "sshAuthorizedKeyType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." } } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } } }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "tableCorsRuleType": { + "type": "object", "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL Role Assignment." + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_sqlDatabases", - "databaseAccount_sqlRoleDefinitions" - ] - }, - "databaseAccount_cassandraRoleDefinitions": { - "copy": { - "name": "databaseAccount_cassandraRoleDefinitions", - "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "roleName": { - "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "dataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" - }, - "notDataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "cassandraRoleAssignments": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10787709019875067397" + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } }, - "name": "DocumentDB Database Account Cassandra Role Definitions.", - "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." - }, - "definitions": { - "cassandraRoleAssignmentType": { + "tableType": { "type": "object", "properties": { "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role assignment." - } - }, - "principalId": { "type": "string", "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." + "description": "Required. The name of the table." } }, - "scope": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + "description": "Optional. Array of role assignments to create." } } }, "metadata": { - "__bicep_export!": true + "description": "The type for a table.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep" + } } } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. Name of the Storage Account. Must be lower-case." } }, - "name": { + "location": { "type": "string", - "nullable": true, + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The unique identifier of the Role Definition." + "description": "Optional. Location for all resources." } }, - "roleName": { + "extendedLocationZone": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." } }, - "dataActions": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "defaultValue": [], + "nullable": true, "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + "description": "Optional. Array of role assignments to create." } }, - "notDataActions": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + "description": "Optional. The managed identity definition for this resource." } }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + "description": "Optional. Type of Storage Account to create." } }, - "cassandraRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" - }, - "nullable": true, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS", + "Standard_GRS", + "Standard_GZRS", + "Standard_RAGRS", + "Standard_RAGZRS", + "StandardV2_LRS", + "StandardV2_ZRS", + "StandardV2_GRS", + "StandardV2_GZRS", + "Premium_LRS", + "Premium_ZRS", + "PremiumV2_LRS", + "PremiumV2_ZRS" + ], "metadata": { - "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" }, - "cassandraRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", - "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ - { - "dataActions": "[parameters('dataActions')]", - "notDataActions": "[parameters('notDataActions')]" - } - ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "Cold" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." } }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "roleDefinitionId": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" - }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "cassandraRoleDefinition" - ] - } - }, - "outputs": { - "name": { + "largeFileSharesState": { "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "The name of the cassandra role definition." - }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } }, - "resourceId": { - "type": "string", + "azureFilesIdentityBasedAuthentication": { + "type": "object", "metadata": { - "description": "The resource ID of the cassandra role definition." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" + }, + "description": "Optional. Provides the identity based authentication settings for Azure Files." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + "nullable": true }, - "resourceGroupName": { - "type": "string", + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The name of the resource group the cassandra role definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, - "name": { - "type": "string", + "managementPolicyRules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Optional. The Storage Account ManagementPolicies Rules." + }, + "nullable": true + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", "nullable": true, "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." } }, - "principalId": { - "type": "string", + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." } }, - "roleDefinitionId": { + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." } }, - "scope": { + "dnsEndpointType": { "type": "string", "nullable": true, + "allowedValues": [ + "AzureDnsZone", + "Standard" + ], "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + "blobServices": { + "$ref": "#/definitions/blobServiceType", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." } - } - }, - "outputs": { - "name": { - "type": "string", + }, + "fileServices": { + "$ref": "#/definitions/fileServiceType", + "defaultValue": {}, "metadata": { - "description": "The name of the Cassandra Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + "description": "Optional. File service and shares to deploy." + } }, - "resourceId": { - "type": "string", + "queueServices": { + "$ref": "#/definitions/queueServiceType", + "defaultValue": {}, "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + "description": "Optional. Queue service and queues to create." + } }, - "resourceGroupName": { - "type": "string", + "tableServices": { + "$ref": "#/definitions/tableServiceType", + "defaultValue": {}, "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_cassandraKeyspaces", - "databaseAccount_cassandraRoleDefinitions" - ] - }, - "databaseAccount_mongodbDatabases": { - "copy": { - "name": "databaseAccount_mongodbDatabases", - "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "collections": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" - }, - "autoscaleSettings": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "13897098552792121791" + "description": "Optional. Table service and tables to create." + } }, - "name": "DocumentDB Database Account MongoDB Databases", - "description": "This module deploys a MongoDB Database within a CosmosDB Account." - }, - "definitions": { - "collectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_export!": true, - "description": "The type of a collection." + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." } - } - }, - "parameters": { - "databaseAccountName": { + }, + "minimumTlsVersion": { "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_2", + "TLS1_3" + ], "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." } }, - "name": { - "type": "string", + "enableHierarchicalNamespace": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Required. Name of the mongodb database." + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." } }, - "throughput": { - "type": "int", - "defaultValue": 400, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/localUserType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + "description": "Optional. Enables local users feature, if set to true." } }, - "collections": { + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/collectionType" + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" }, "nullable": true, "metadata": { - "description": "Optional. Collections in the mongodb database." + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" }, "description": "Optional. Tags of the resource." }, "nullable": true }, - "autoscaleSettings": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "sasExpirationAction": { + "type": "string", + "defaultValue": "Log", + "allowedValues": [ + "Block", + "Log" + ], + "metadata": { + "description": "Optional. The SAS expiration action. Allowed values are Block and Log." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "immutableStorageWithVersioning": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." }, "nullable": true + }, + "objectReplicationPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Object replication policies for the storage account." + } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + }, "resources": { - "databaseAccount": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" }, - "mongodbDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2025-05-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "databaseAccount" + "storageAccount" + ] + }, + "storageAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "storageAccount" ] }, - "mongodbDatabase_collections": { + "storageAccount_privateEndpoints": { "copy": { - "name": "mongodbDatabase_collections", - "count": "[length(coalesce(parameters('collections'), createArray()))]" + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, - "mongodbDatabaseName": { - "value": "[parameters('name')]" + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "name": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" }, - "indexes": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, - "shardKey": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, - "throughput": { - "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "16151461445994734468" + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "DocumentDB Database Account MongoDB Database Collections", - "description": "This module deploys a MongoDB Database Collection." + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "mongodbDatabaseName": { + "subnetResourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "name": { - "type": "string", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Required. Name of the collection." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "throughput": { - "type": "int", - "defaultValue": 400, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "indexes": { + "ipConfigurations": { "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" }, - "description": "Required. Indexes for the collection." + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } }, - "shardKey": { + "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" }, - "description": "Required. ShardKey for the collection." + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]", - "indexes": "[parameters('indexes')]", - "shardKey": "[parameters('shardKey')]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" } } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] } - ], + }, "outputs": { - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the mongodb database collection." + "description": "The resource group the private endpoint was deployed into." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the mongodb database collection." + "description": "The resource ID of the private endpoint." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the mongodb database collection was created in." + "description": "The name of the private endpoint." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "mongodbDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the mongodb database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the mongodb database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the mongodb database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_gremlinDatabases": { - "copy": { - "name": "databaseAccount_gremlinDatabases", - "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "graphs": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" - }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11959636451300474346" - }, - "name": "DocumentDB Database Account Gremlin Databases", - "description": "This module deploys a Gremlin Database within a CosmosDB Account." - }, - "definitions": { - "graphType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + "value": "[parameters('name')]" }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a graph." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin database resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." - } - }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "gremlinDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } } }, "dependsOn": [ - "databaseAccount" + "storageAccount" ] }, - "gremlinDatabase_gremlinGraphs": { - "copy": { - "name": "gremlinDatabase_gremlinGraphs", - "count": "[length(coalesce(parameters('graphs'), createArray()))]" - }, + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" - }, - "gremlinDatabaseName": { + "storageAccountName": { "value": "[parameters('name')]" }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" + "rules": { + "value": "[variables('formattedManagementPolicies')]" }, - "partitionKeyPaths": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10487122333182352122" + "version": "0.41.2.15936", + "templateHash": "4000605059554016072" }, - "name": "DocumentDB Database Accounts Gremlin Databases Graphs", - "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." }, "parameters": { - "name": { + "storageAccountName": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Required. Name of the graph." + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "tags": { - "type": "object", + "rules": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. The Storage Account ManagementPolicies Rules." } }, - "gremlinDatabaseName": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true } }, - "resources": { - "databaseAccount::gremlinDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "gremlinGraph": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { - "resource": { - "id": "[parameters('name')]", - "indexingPolicy": "[parameters('indexingPolicy')]", - "partitionKey": { - "paths": "[parameters('partitionKeyPaths')]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the graph." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the graph." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the graph was created in." - }, - "value": "[resourceGroup().name]" + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } } - } - } - }, - "dependsOn": [ - "gremlinDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Gremlin database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Gremlin database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Gremlin database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_tables": { - "copy": { - "name": "databaseAccount_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1787500858429182824" - }, - "name": "Azure Cosmos DB account tables", - "description": "This module deploys a table within an Azure Cosmos DB Account." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" - }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "table": { - "type": "Microsoft.DocumentDB/databaseAccounts/tables", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" - } - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraKeyspaces": { - "copy": { - "name": "databaseAccount_cassandraKeyspaces", - "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "tables": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" - }, - "views": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15257396763463366586" - }, - "name": "DocumentDB Database Account Cassandra Keyspaces", - "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." - }, - "definitions": { - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "schema": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Analytical TTL for the table." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra table." - } - }, - "viewType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the view." - } - }, - "viewDefinition": { - "type": "string", - "metadata": { - "description": "Required. View definition (CQL statement)." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags for the view." - }, - "nullable": true - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra view (materialized view)." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Cassandra keyspace." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra keyspace resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." - } - }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/viewType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraKeyspace": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } } }, "dependsOn": [ - "databaseAccount" + "storageAccount", + "storageAccount_blobServices" ] }, - "cassandraKeyspace_tables": { + "storageAccount_localUsers": { "copy": { - "name": "cassandraKeyspace_tables", - "count": "[length(parameters('tables'))]" + "name": "storageAccount_localUsers", + "count": "[length(coalesce(parameters('localUsers'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[parameters('tables')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { + "storageAccountName": { "value": "[parameters('name')]" }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" }, - "schema": { - "value": "[parameters('tables')[copyIndex()].schema]" + "hasSshKey": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" }, - "analyticalStorageTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + "hasSshPassword": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" }, - "throughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + "permissionScopes": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + "hasSharedKey": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" }, - "defaultTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + "homeDirectory": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" }, - "tags": { - "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + "sshAuthorizedKeys": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -55498,274 +57352,1425 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15998065591386988132" + "version": "0.41.2.15936", + "templateHash": "1801226901235196767" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } }, - "name": "DocumentDB Database Account Cassandra Keyspaces Tables", - "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } }, "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, "name": { "type": "string", "metadata": { - "description": "Required. Name of the Cassandra table." + "description": "Required. The name of the local user used for SFTP Authentication." } }, - "tags": { + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "468225492069709453" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." + }, + "definitions": { + "corsRuleType": { "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a storage container." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "container/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } }, - "description": "Optional. Tags of the Cassandra table resource." + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } - }, - "cassandraKeyspaceName": { + } + }, + "parameters": { + "storageAccountName": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "schema": { - "type": "object", + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the Cassandra table." + "description": "Optional. Automatic Snapshot is enabled if set to true." } }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." } }, - "throughput": { + "changeFeedRetentionInDays": { "type": "int", "nullable": true, + "minValue": 1, + "maxValue": 146000, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." } }, - "defaultTtl": { + "containerDeleteRetentionPolicyDays": { "type": "int", - "defaultValue": 0, + "nullable": true, + "minValue": 1, + "maxValue": 365, "metadata": { - "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + "description": "Optional. Indicates the number of days that the deleted item should be retained." } - } - }, - "resources": { - "databaseAccount::cassandraKeyspace": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } }, - "cassandraTable": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "schema": "[parameters('schema')]", - "defaultTtl": "[parameters('defaultTtl')]", - "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", + "nullable": true, "metadata": { - "description": "The name of the Cassandra table." - }, - "value": "[parameters('name')]" + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } }, - "resourceId": { + "defaultServiceVersion": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource ID of the Cassandra table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } }, - "resourceGroupName": { - "type": "string", + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "The name of the resource group the Cassandra table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "cassandraKeyspace" - ] - }, - "cassandraKeyspace_views": { - "copy": { - "name": "cassandraKeyspace_views", - "count": "[length(parameters('views'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('views')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "viewDefinition": { - "value": "[parameters('views')[copyIndex()].viewDefinition]" - }, - "throughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "6617803098467821091" + "description": "Optional. The blob service properties for blob soft delete." + } }, - "name": "DocumentDB Database Account Cassandra Keyspaces Views", - "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." - }, - "parameters": { - "name": { - "type": "string", + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, "metadata": { - "description": "Required. Name of the Cassandra view." + "description": "Optional. Indicates the number of days that the deleted blob should be retained." } }, - "tags": { - "type": "object", + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags of the Cassandra view resource." - }, - "nullable": true + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } }, - "databaseAccountName": { - "type": "string", + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." } }, - "cassandraKeyspaceName": { - "type": "string", + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." } }, - "viewDefinition": { - "type": "string", + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." } }, - "throughput": { + "restorePolicyDays": { "type": "int", - "nullable": true, + "defaultValue": 7, + "minValue": 1, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + "description": "Optional. Blob containers to create." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. The diagnostic settings of the service." } } }, + "variables": { + "enableReferencedModulesTelemetry": false, + "name": "default" + }, "resources": { - "databaseAccount::cassandraKeyspace": { + "storageAccount": { "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-05-01-preview", - "name": "[parameters('databaseAccountName')]" + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[parameters('defaultServiceVersion')]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] }, - "cassandraView": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { - "resource": { - "id": "[parameters('name')]", - "viewDefinition": "[parameters('viewDefinition')]" + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "273904034769611992" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an immutability policy." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "defaultValue": {} + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "container_immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15304742179563677019" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } }, "dependsOn": [ - "databaseAccount" + "blobServices" ] } }, @@ -55773,21 +58778,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the Cassandra view." + "description": "The name of the deployed blob service." }, - "value": "[parameters('name')]" + "value": "[variables('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Cassandra view." + "description": "The resource ID of the deployed blob service." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the Cassandra view was created in." + "description": "The name of the deployed blob service." }, "value": "[resourceGroup().name]" } @@ -55795,512 +58800,37 @@ } }, "dependsOn": [ - "cassandraKeyspace" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra keyspace." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra keyspace." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra keyspace was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_privateEndpoints": { - "copy": { - "name": "databaseAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" + "storageAccount" ] }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "storageAccountName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + }, + "corsRules": { + "value": "[tryGet(parameters('fileServices'), 'corsRules')]" } }, "template": { @@ -56310,1620 +58840,1752 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "version": "0.41.2.15936", + "templateHash": "17583198711200998285" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." }, "definitions": { - "privateDnsZoneGroupConfigType": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "fileShareType": { "type": "object", "properties": { "name": { "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." } }, - "privateDnsZoneResourceId": { + "enabledProtocols": { "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." + "description": "The type for a file share." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } } }, "parameters": { - "privateEndpointName": { + "storageAccountName": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "privateDnsZoneConfigs": { + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." + }, + "defaultValue": {} + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "defaultValue": { + "enabled": true, + "days": 7 + } + }, + "corsRules": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/corsRuleType" }, - "minLength": 1, - "maxLength": 5, + "nullable": true, "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." } }, - "name": { - "type": "string", - "defaultValue": "default", + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." } } }, + "variables": { + "enableReferencedModulesTelemetry": false + }, "resources": { - "privateEndpoint": { + "storageAccount": { "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "provisionedBandwidthMibps": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + }, + "provisionedIops": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10353179772982843397" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the database account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the database account." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the database account was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the database account." - }, - "value": "[reference('databaseAccount').documentEndpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the database account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "primaryReadWriteKey": { - "type": "securestring", - "metadata": { - "description": "The primary read-write key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" - }, - "primaryReadOnlyKey": { - "type": "securestring", - "metadata": { - "description": "The primary read-only key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" - }, - "primaryReadWriteConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary read-write connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" - }, - "primaryReadOnlyConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary read-only connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" - }, - "secondaryReadWriteKey": { - "type": "securestring", - "metadata": { - "description": "The secondary read-write key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" - }, - "secondaryReadOnlyKey": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only key." - }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" - }, - "secondaryReadWriteConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary read-write connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" - }, - "secondaryReadOnlyConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" - } - } - } - }, - "dependsOn": [ - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", - "virtualNetwork" - ] - }, - "avmAiSearch": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "name": { - "value": "[format('srch-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "skuName": { - "value": "basic" - }, - "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", - "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8530209533589901450" - } - }, - "parameters": { - "solutionName": { - "type": "string", - "minLength": 3, - "metadata": { - "description": "Solution name suffix used to derive the resource name." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", - "metadata": { - "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region for the resource." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resource." - } - }, - "skuName": { - "type": "string", - "defaultValue": "basic", - "allowedValues": [ - "free", - "basic", - "standard", - "standard2", - "standard3", - "storage_optimized_l1", - "storage_optimized_l2" - ], - "metadata": { - "description": "SKU name for the search service." - } - }, - "replicaCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of replicas." - } - }, - "partitionCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of partitions." - } - }, - "hostingMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "HighDensity" - ], - "metadata": { - "description": "Hosting mode." - } - }, - "semanticSearch": { - "type": "string", - "defaultValue": "free", - "allowedValues": [ - "disabled", - "free", - "standard" - ], - "metadata": { - "description": "Semantic search tier." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Whether to disable local authentication." - } - }, - "managedIdentityType": { - "type": "string", - "defaultValue": "SystemAssigned", - "metadata": { - "description": "Managed identity type for the search service." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Public network access setting." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Diagnostic settings for monitoring." - } - }, - "privateEndpoints": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Private endpoint configurations." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of role assignments to create on the AI Search service." - } - } - }, - "resources": { - "searchService": { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "[parameters('skuName')]" - } - }, - "searchServiceUpdate": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.search.update.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "sku": { - "value": "[parameters('skuName')]" - }, - "replicaCount": { - "value": "[parameters('replicaCount')]" - }, - "partitionCount": { - "value": "[parameters('partitionCount')]" - }, - "hostingMode": { - "value": "[parameters('hostingMode')]" - }, - "semanticSearch": { - "value": "[parameters('semanticSearch')]" - }, - "disableLocalAuth": { - "value": "[parameters('disableLocalAuth')]" - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": "[equals(parameters('managedIdentityType'), 'SystemAssigned')]" - } - }, - "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "6207719545398489494" - }, - "name": "Search Services", - "description": "This module deploys a Search Service." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]", + "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", + "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } + "dependsOn": [ + "fileServices", + "storageAccount" + ] } }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the API Admin keys generated by the modules." - } - }, - "primaryAdminKeyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primaryAdminKey secret name to create." - } - }, - "secondaryAdminKeyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The secondaryAdminKey secret name to create." - } - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/secretSetType", - "metadata": { - "description": "An exported secret's references." - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" }, - "privateIPAddress": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "dependsOn": [ + "storageAccount" + ] }, - "secretSetType": { - "type": "object", + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + }, + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "modules/keyVaultExport.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." - } - }, - "authOptions": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/authOptions" - }, - "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." - }, - "nullable": true - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "computeType": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Confidential", - "Default" - ], - "metadata": { - "description": "Optional. The compute type of the search service." - } - }, - "cmkEnforcement": { - "type": "string", - "defaultValue": "Unspecified", - "allowedValues": [ - "Disabled", - "Enabled", - "Unspecified" - ], - "metadata": { - "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." - } - }, - "dataExfiltrationProtections": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "allowedValues": [ - "All" - ], - "metadata": { - "description": "Optional. A list of data exfiltration scenarios that are explicitly disallowed for the search service. Currently, the only supported value is 'All' to disable all possible data export scenarios with more fine grained controls planned for the future." - } - }, - "hostingMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "HighDensity" - ], - "metadata": { - "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings for all Resources in the solution." - } - }, - "networkRuleSet": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/networkRuleSet" - }, - "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." - }, - "nullable": true - }, - "partitionCount": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 12, - "metadata": { - "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "sharedPrivateLinkResources": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "replicaCount": { - "type": "int", - "defaultValue": 3, - "minValue": 1, - "maxValue": 12, - "metadata": { - "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "semanticSearch": { - "type": "string", - "nullable": true, - "allowedValues": [ - "disabled", - "free", - "standard" - ], - "metadata": { - "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." - } - }, - "sku": { - "type": "string", - "defaultValue": "standard", - "allowedValues": [ - "basic", - "free", - "standard", - "standard2", - "standard3", - "storage_optimized_l1", - "storage_optimized_l2" - ], - "metadata": { - "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Search/searchServices@2025-05-01#properties/tags" }, - "description": "Optional. Tags to help categorize the resource in the Azure portal." - }, - "nullable": true - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', '')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", - "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", - "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9644461291744477521" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a queue." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } } - } - } - } - }, - "searchService": { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "[parameters('sku')]" - }, - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "authOptions": "[parameters('authOptions')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryptionWithCmk": { - "enforcement": "[parameters('cmkEnforcement')]" - }, - "hostingMode": "[parameters('hostingMode')]", - "networkRuleSet": "[parameters('networkRuleSet')]", - "partitionCount": "[parameters('partitionCount')]", - "replicaCount": "[parameters('replicaCount')]", - "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", - "semanticSearch": "[parameters('semanticSearch')]", - "computeType": "[parameters('computeType')]", - "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" - } - }, - "searchService_diagnosticSettings": { - "copy": { - "name": "searchService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "12812824360066955039" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair that represents queue metadata." + }, + "defaultValue": {} + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue service." + }, + "value": "[resourceGroup().name]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "searchService" - ] - }, - "searchService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "searchService" - ] - }, - "searchService_roleAssignments": { - "copy": { - "name": "searchService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } }, "dependsOn": [ - "searchService" + "storageAccount" ] }, - "searchService_privateEndpoints": { - "copy": { - "name": "searchService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "storageAccountName": { + "value": "[parameters('name')]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "corsRules": { + "value": "[tryGet(parameters('tableServices'), 'corsRules')]" } }, "template": { @@ -57933,96 +60595,217 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" + "version": "0.41.2.15936", + "templateHash": "10320403358700650147" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." }, "definitions": { - "privateDnsZoneGroupType": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "tableType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Required. The name of the table." } }, - "privateDnsZoneGroupConfigs": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Array of role assignments to create." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a private dns zone group." + "description": "The type for a table." } }, - "lockType": { + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The name of the diagnostic setting." } }, - "kind": { + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" + "AzureDiagnostics", + "Dedicated" ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "notes": { + "workspaceResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { + }, + "storageAccountResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "privateDnsZoneResourceId": { + "eventHubAuthorizationRuleResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "description": "The type of a private DNS zone group configuration.", + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -58103,233 +60886,112 @@ } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { + "storageAccountName": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "applicationSecurityGroupResourceIds": { + "tables": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/tableType" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Tables to create." } }, - "ipConfigurations": { + "corsRules": { "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "items": { + "$ref": "#/definitions/corsRuleType" }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." } }, - "roleAssignments": { + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/diagnosticSettingFullType" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The diagnostic settings of the service." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "name": "default", + "enableReferencedModulesTelemetry": false }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { "copy": [ { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "privateEndpoint" + "tableServices" ] }, - "privateEndpoint_roleAssignments": { + "tableServices_tables": { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "name": "tableServices_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -58337,13 +60999,16 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" }, - "privateEndpointName": { - "value": "[parameters('name')]" + "storageAccountName": { + "value": "[parameters('storageAccountName')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -58353,217 +61018,278 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "version": "0.41.2.15936", + "templateHash": "11362260974696477885" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." }, "definitions": { - "privateDnsZoneGroupConfigType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "privateDnsZoneResourceId": { + "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } } }, "parameters": { - "privateEndpointName": { + "storageAccountName": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "privateDnsZoneConfigs": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, - "maxLength": 5, + "nullable": true, "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Array of role assignments to create." } }, "name": { "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Required. Name of the table." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, "resources": { - "privateEndpoint": { + "storageAccount::tableServices": { "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } - ] + } } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the deployed table." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the deployed table." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The resource group of the deployed table." }, "value": "[resourceGroup().name]" } } } - }, - "dependsOn": [ - "privateEndpoint" - ] + } } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The name of the deployed table service." }, - "value": "[parameters('name')]" + "value": "[variables('name')]" }, - "location": { + "resourceId": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The resource ID of the deployed table service." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" }, - "groupId": { + "resourceGroupName": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The resource group of the deployed table service." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "searchService" + "storageAccount" ] }, - "searchService_sharedPrivateLinkResources": { - "copy": { - "name": "searchService_sharedPrivateLinkResources", - "count": "[length(parameters('sharedPrivateLinkResources'))]", - "mode": "serial", - "batchSize": 1 - }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" - }, - "searchServiceName": { - "value": "[parameters('name')]" - }, - "privateLinkResourceId": { - "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" - }, - "groupId": { - "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" - }, - "requestMessage": { - "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" }, - "resourceRegion": { - "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" } }, "template": { @@ -58573,117 +61299,151 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "2115224445601868607" - }, - "name": "Search Services Private Link Resources", - "description": "This module deploys a Search Service Private Link Resource." + "version": "0.41.2.15936", + "templateHash": "13227497656004178962" + } }, - "parameters": { - "searchServiceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." - } - }, - "privateLinkResourceId": { - "type": "string", + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, "metadata": { - "description": "Required. The resource ID of the resource the shared private link resource is for." + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } } }, - "groupId": { - "type": "string", + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, "metadata": { - "description": "Required. The group ID from the provider of resource the shared private link resource is for." + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } } - }, - "requestMessage": { + } + }, + "parameters": { + "keyVaultName": { "type": "string", "metadata": { - "description": "Required. The request message for requesting approval of the shared private link resource." + "description": "Required. The name of the Key Vault to set the ecrets in." } }, - "resourceRegion": { - "type": "string", - "nullable": true, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, "metadata": { - "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + "description": "Required. The secrets to set in the Key Vault." } } }, "resources": { - "searchService": { + "keyVault": { "existing": true, - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", - "name": "[parameters('searchServiceName')]" + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" }, - "sharedPrivateLinkResource": { - "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", "properties": { - "privateLinkResourceId": "[parameters('privateLinkResourceId')]", - "groupId": "[parameters('groupId')]", - "requestMessage": "[parameters('requestMessage')]", - "resourceRegion": "[parameters('resourceRegion')]" + "value": "[parameters('secretsToSet')[copyIndex()].value]" } } }, "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the shared private link resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the shared private link resource." + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" }, - "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the shared private link resource was created in." + "description": "The references to the secrets exported to the provided Key Vault." }, - "value": "[resourceGroup().name]" + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } } } } }, "dependsOn": [ - "searchService" + "storageAccount" ] }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "storageAccount_objectReplicationPolicies": { + "copy": { + "name": "storageAccount_objectReplicationPolicies", + "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + "storageAccountName": { + "value": "[parameters('name')]" }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + "destinationAccountResourceId": { + "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" + }, + "enableMetrics": { + "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" + }, + "rules": { + "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" } }, "template": { @@ -58693,1890 +61453,1004 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "696453183181258843" - } + "version": "0.41.2.15936", + "templateHash": "1894366578172550759" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." }, "definitions": { - "secretSetType": { + "objectReplicationPolicyRuleType": { "type": "object", "properties": { - "secretResourceId": { + "ruleId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resourceId of the exported secret." + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." } }, - "secretUri": { + "containerName": { "type": "string", "metadata": { - "description": "The secret URI of the exported secret." + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "policy/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the parent Storage Account." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "variables": { + "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", + "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", + "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", + "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "destinationPolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", + "subscriptionId": "[variables('destAccountSubscription')]", + "resourceGroup": "[variables('destAccountResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('name'), 'default')]" + }, + "storageAccountName": { + "value": "[variables('destAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "value": "[parameters('rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } } } - }, - "metadata": { - "__bicep_export!": true } }, - "secretToSetType": { - "type": "object", + "sourcePolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" - } - } - } - } - } - }, - "dependsOn": [ - "searchService" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the search service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the search service." - }, - "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the search service was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('searchService', '2025-05-01', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the search service." - }, - "value": "[reference('searchService').endpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the search service." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "primaryKey": { - "type": "securestring", - "metadata": { - "description": "The primary admin API key of the search service." - }, - "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" - }, - "secondaryKey": { - "type": "securestring", - "metadata": { - "description": "The secondaryKey admin API key of the search service." - }, - "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" - } - } - } - }, - "dependsOn": [ - "searchService" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the AI Search service." - }, - "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "Name of the AI Search service." - }, - "value": "[parameters('name')]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "Endpoint URL of the AI Search service." - }, - "value": "[format('https://{0}.search.windows.net', parameters('name'))]" - }, - "identityPrincipalId": { - "type": "string", - "metadata": { - "description": "System-assigned identity principal ID." - }, - "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" - } - } - } - } - }, - "avmAppConfig": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('location')]" - } - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "sku": { - "value": "Standard" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "disableLocalAuth": { - "value": false - }, - "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - } - ] - }, - "keyValues": { - "value": [ - { - "name": "APP_AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_AZURE_OPENAI_MODEL", - "value": "[parameters('gptModelName')]" - }, - { - "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_COSMOS_CONTAINER_PROCESS", - "value": "Processes" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMA", - "value": "Schemas" - }, - { - "name": "APP_COSMOS_DATABASE", - "value": "ContentProcess" - }, - { - "name": "APP_CPS_CONFIGURATION", - "value": "cps-configuration" - }, - { - "name": "APP_CPS_MAX_FILESIZE_MB", - "value": "20" - }, - { - "name": "APP_CPS_PROCESSES", - "value": "cps-processes" - }, - { - "name": "APP_MESSAGE_QUEUE_EXTRACT", - "value": "content-pipeline-extract-queue" - }, - { - "name": "APP_MESSAGE_QUEUE_INTERVAL", - "value": "5" - }, - { - "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", - "value": "180" - }, - { - "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", - "value": "10" - }, - { - "name": "APP_PROCESS_STEPS", - "value": "extract,map,evaluate,save" - }, - { - "name": "APP_STORAGE_BLOB_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" - }, - { - "name": "APP_STORAGE_QUEUE_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" - }, - { - "name": "APP_AI_PROJECT_ENDPOINT", - "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" - }, - { - "name": "APP_COSMOS_CONNSTR", - "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", - "value": "claimprocesses" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCHES", - "value": "batches" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMASET", - "value": "Schemasets" - }, - { - "name": "APP_CPS_PROCESS_BATCH", - "value": "process-batch" - }, - { - "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", - "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" - }, - { - "name": "APP_CPS_POLL_INTERVAL_SECONDS", - "value": "3" - }, - { - "name": "APP_STORAGE_ACCOUNT_NAME", - "value": "[reference('avmStorageAccount').outputs.name.value]" - }, - { - "name": "CLAIM_PROCESS_QUEUE_NAME", - "value": "claim-process-queue" - }, - { - "name": "DEAD_LETTER_QUEUE_NAME", - "value": "claim-process-dead-letter-queue" - }, - { - "name": "AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", - "value": "[parameters('gptModelName')]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "AZURE_OPENAI_ENDPOINT_BASE", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", - "value": "" - }, - { - "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", - "value": "" - }, - { - "name": "AZURE_TRACING_ENABLED", - "value": "True" - }, - { - "name": "GLOBAL_LLM_SERVICE", - "value": "AzureOpenAI" - }, - { - "name": "GPT5_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "GPT5_CHAT_DEPLOYMENT_NAME", - "value": "gpt-5" - }, - { - "name": "GPT5_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "PHI4_API_VERSION", - "value": "2024-05-01-preview" - }, - { - "name": "PHI4_CHAT_DEPLOYMENT_NAME", - "value": "phi-4" - }, - { - "name": "PHI4_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - } - ] - }, - "publicNetworkAccess": { - "value": "Enabled" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } - }, - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[reference('destinationPolicy').outputs.policyId.value]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('rules'))]", + "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } + } + } + }, + "dependsOn": [ + "destinationPolicy" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.policyId.value]" + } + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] } }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" }, - "memberName": { + "name": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" }, - "privateIPAddress": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + "description": "The resource group of the deployed storage account." }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2025-06-01', 'full').location]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." + }, + "value": "[reference('storageAccount').primaryEndpoints]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Storage Account." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" } } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The primary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + }, + "secondaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The secondary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" + }, + "primaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" + }, + "secondaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } + "description": "Resource ID of the storage account." }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } + "value": "[reference('storageAccount').outputs.resourceId.value]" }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, + "name": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "description": "Name of the storage account." + }, + "value": "[reference('storageAccount').outputs.name.value]" }, - "roleAssignmentType": { + "serviceEndpoints": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } + "description": "Service endpoints exposed by the storage account." + }, + "value": "[reference('storageAccount').outputs.serviceEndpoints.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageQueue), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageBlob), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.cosmos-db-mongo.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "databaseName": { + "value": "default" + }, + "collections": { + "value": [] + }, + "serverVersion": { + "value": "7.0" + }, + "consistencyLevel": { + "value": "Session" + }, + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "enableAutomaticFailover": { + "value": "[parameters('enableRedundancy')]" + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cosmosDB), 64)), '2025-04-01').outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7370292565038719427" } }, "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, "name": { "type": "string", + "defaultValue": "[format('cosmos-{0}', parameters('solutionName'))]", "metadata": { - "description": "Required. Name of the Azure App Configuration." + "description": "Name of the Cosmos DB account." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Azure region for the resource." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Tags to apply to the resource." } }, - "sku": { + "databaseName": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], + "defaultValue": "default", "metadata": { - "description": "Optional. Pricing tier of App Configuration." + "description": "MongoDB database name." } }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], + "collections": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." + "description": "MongoDB collections to create." } }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, + "serverVersion": { + "type": "string", + "defaultValue": "7.0", + "allowedValues": [ + "4.2", + "5.0", + "6.0", + "7.0" + ], "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." + "description": "MongoDB server version." } }, - "enablePurgeProtection": { + "enableAnalyticalStorage": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + "description": "Enable analytical storage (Synapse Link)." } }, - "publicNetworkAccess": { + "consistencyLevel": { "type": "string", - "nullable": true, + "defaultValue": "Session", "allowedValues": [ - "Enabled", - "Disabled" + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + "description": "Default consistency level." } }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The customer managed key definition." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "keyValues": { + "diagnosticSettings": { "type": "array", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + "description": "Diagnostic settings for monitoring." } }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. All Replicas to create." + "description": "Public network access setting." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Whether to enable private networking." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "privateEndpointSubnetId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Subnet resource ID for the private endpoint." } }, - "roleAssignments": { + "privateDnsZoneResourceIds": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Private DNS zone resource IDs for Cosmos DB (MongoDB)." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + "description": "Enable zone redundancy." } }, - "enableTelemetry": { + "enableAutomaticFailover": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Enable automatic failover." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "haLocation": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. HA paired region for multi-region failover when redundancy is enabled." } } }, "variables": { "copy": [ { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('dns-zone-{0}', copyIndex('privateDnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + ] }, "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "cosmosAccount": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.document-db.database-account.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + "value": "[parameters('name')]" }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + "location": { + "value": "[parameters('location')]" }, "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" - }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." + "value": "[parameters('tags')]" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the key." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. The value of the key-value." - } - }, - "appConfigurationName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } - }, - "contentType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "resources": { - "appConfiguration": { - "existing": true, - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" - }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" - } - } + "capabilitiesToAdd": { + "value": [ + "EnableMongo" + ] }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key values." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key values." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the batch account was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" + "serverVersion": { + "value": "[parameters('serverVersion')]" }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + "enableAnalyticalStorage": { + "value": "[parameters('enableAnalyticalStorage')]" }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" - }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." + "defaultConsistencyLevel": { + "value": "[parameters('consistencyLevel')]" }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", - "metadata": { - "description": "Optional. Name of the replica." - } - }, - "appConfigurationName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } - }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." + "mongodbDatabases": { + "value": [ + { + "name": "[parameters('databaseName')]", + "collections": "[parameters('collections')]" } - } + ] }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the replica that was deployed." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the replica that was deployed." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", + "networkRestrictions": { + "value": { + "networkAclBypass": "None", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-{0}', parameters('name')), 'customNetworkInterfaceName', format('nic-{0}', parameters('name')), 'subnetResourceId', parameters('privateEndpointSubnetId'), 'service', 'MongoDB', 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', variables('privateDnsZoneConfigs'))))), createObject('value', createArray()))]", + "zoneRedundant": { + "value": "[parameters('zoneRedundant')]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "enableAutomaticFailover": { + "value": "[parameters('enableAutomaticFailover')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } + "failoverLocations": "[if(and(parameters('zoneRedundant'), not(empty(parameters('haLocation')))), createObject('value', createArray(createObject('failoverPriority', 0, 'isZoneRedundant', true(), 'locationName', parameters('location')), createObject('failoverPriority', 1, 'isZoneRedundant', true(), 'locationName', parameters('haLocation')))), createObject('value', createArray(createObject('locationName', parameters('location'), 'failoverPriority', 0, 'isZoneRedundant', false()))))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -60585,2758 +62459,4542 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.40.2.10011", + "templateHash": "1772014800591596213" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Azure Cosmos DB account", + "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." }, "definitions": { - "privateDnsZoneGroupType": { + "privateEndpointOutputType": { "type": "object", "properties": { "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "The group ID for the private endpoint group." } }, - "privateDnsZoneGroupConfigs": { + "customDnsConfigs": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses for the private endpoint." + } + } + } }, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type for the private endpoint output." } }, - "ipConfigurationType": { + "failoverLocationType": { + "type": "object", + "properties": { + "failoverPriority": { + "type": "int", + "metadata": { + "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." + } + }, + "isZoneRedundant": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." + } + }, + "locationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the region." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the failover location." + } + }, + "sqlRoleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Optional. The unique name of the role assignment." } }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, + "roleDefinitionId": { + "type": "string", "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." } }, - "privateLinkServiceConnectionType": { + "sqlRoleDefinitionType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. The unique identifier of the role-based access control definition." } }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/nestedSqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." + } + }, + "networkRestrictionType": { + "type": "object", + "properties": { + "ipRules": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." + } + }, + "networkAclBypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." + } + }, + "publicNetworkAccess": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." + } + }, + "virtualNetworkRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of a subnet." + } } } }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." } }, - "ipAddresses": { + "networkAclBypassResourceIds": { "type": "array", "items": { "type": "string" }, + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type for the network restriction." } }, - "lockType": { + "gremlinDatabaseType": { "type": "object", "properties": { "name": { "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. Array of graphs to deploy in the Gremlin database." } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], + "maxThroughput": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } + "__bicep_export!": true, + "description": "The type for a gremlin databae." } }, - "privateDnsZoneGroupConfigType": { + "mongoDbType": { "type": "object", "properties": { "name": { "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." } }, - "privateDnsZoneResourceId": { - "type": "string", + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Collections in the mongodb database." } + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } + "__bicep_export!": true, + "description": "The type for a mongo databae." } }, - "roleAssignmentType": { + "sqlDatabaseType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Required. Name of the SQL database ." } }, - "roleDefinitionIdOrName": { - "type": "string", + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. Array of containers to deploy in the SQL database." } }, - "principalId": { - "type": "string", + "throughput": { + "type": "int", + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." } }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], + "autoscaleSettingsMaxThroughput": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." } }, - "description": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a sql database." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Required. Name of the table." } }, - "condition": { - "type": "string", - "nullable": true, + "tags": { + "type": "object", "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], + "maxThroughput": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "throughput": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "__bicep_export!": true, + "description": "The type for a table." } }, - "tags": { + "cassandraStandaloneRoleAssignmentType": { "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "principalId": { + "type": "string", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." } } }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." + } }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." + "cassandraRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" + "cassandraKeyspaceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraTableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraViewType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + } }, "metadata": { - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB Cassandra keyspace." + } }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" + "defaultIdentityType": { + "type": "object", + "discriminator": { + "propertyName": "name", + "mapping": { + "FirstPartyIdentity": { + "$ref": "#/definitions/defaultIdentityFirstPartyType" + }, + "SystemAssignedIdentity": { + "$ref": "#/definitions/defaultIdentitySystemAssignedType" + }, + "UserAssignedIdentity": { + "$ref": "#/definitions/defaultIdentityUserAssignedType" + } + } }, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "__bicep_export!": true, + "description": "The type for the default identity." + } }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the app configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the app configuration." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration store was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the app configuration." - }, - "value": "[reference('configurationStore').endpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the app configuration." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "avmAiServices", - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Web", - "avmContainerApp_Workflow", - "avmCosmosDB", - "avmStorageAccount", - "logAnalyticsWorkspace" - ] - }, - "avmAppConfig_update": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "publicNetworkAccess": { - "value": "Disabled" - }, - "privateEndpoints": { - "value": [ - { - "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", - "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", - "privateDnsZoneGroup": { - "privateDnsZoneGroupConfigs": [ - { - "name": "appconfig-dns-zone-group", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" - } - ] - }, - "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } - }, - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "defaultIdentityFirstPartyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "FirstPartyIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + } + }, + "defaultIdentitySystemAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "SystemAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } + } + }, + "defaultIdentityUserAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "UserAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the user assigned identity to use as the default identity." + } } } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "memberName": { - "type": "string", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "privateIPAddress": { - "type": "string", + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-role-definition/main.bicep" + } } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + }, + "cassandraTableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "metadata": { + "description": "The type of a Cassandra table.", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "tableType" } } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + }, + "cassandraViewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "description": "The type of a Cassandra view (materialized view).", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "viewType" + } + } + }, + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "description": "The type of a collection.", + "__bicep_imported_from!": { + "sourceTemplate": "mongodb-database/main.bicep" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "The type of a container.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-database/main.bicep" + } + } + }, + "customerManagedKeyAndVaultOnlyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "description": "The type of a graph.", + "__bicep_imported_from!": { + "sourceTemplate": "gremlin-database/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure App Configuration." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], - "metadata": { - "description": "Optional. Pricing tier of App Configuration." - } - }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], - "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "keyValues": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." - } - }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All Replicas to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, - "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" - }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "nestedSqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "description": "The type for the SQL Role Assignments.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-role-definition/main.bicep", + "originalIdentifier": "sqlRoleAssignmentType" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the key." + "description": "Required. The name of the account." } }, - "value": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Defaults to the current resource group scope location. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "databaseAccountOfferType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], + "metadata": { + "description": "Optional. The offer type for the account. Defaults to \"Standard\"." + } + }, + "failoverLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/failoverLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." + } + }, + "defaultConsistencyLevel": { + "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], + "metadata": { + "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." + } + }, + "disableLocalAuthentication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." + } + }, + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." + } + }, + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions. Defaults to true." + } + }, + "enableFreeTier": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." + } + }, + "enableMultipleWriteLocations": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." + } + }, + "disableKeyBasedMetadataWriteAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." + } + }, + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." + } + }, + "serverVersion": { + "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2", + "5.0", + "6.0", + "7.0" + ], + "metadata": { + "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." + } + }, + "sqlDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." + } + }, + "mongodbDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/mongoDbType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." + } + }, + "gremlinDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/gremlinDatabaseType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." + } + }, + "cassandraKeyspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraKeyspaceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "totalThroughputLimit": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of control plane Azure role-based access control assignments." + } + }, + "sqlRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." + } + }, + "cassandraRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleDefinitionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings for the service." + } + }, + "capabilitiesToAdd": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless", + "EnableNoSQLVectorSearch", + "EnableNoSQLFullTextSearch", + "EnableMaterializedViews", + "DeleteAllItemsByPartitionKey" + ], + "metadata": { + "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." + } + }, + "backupPolicyType": { + "type": "string", + "defaultValue": "Continuous", + "allowedValues": [ + "Periodic", + "Continuous" + ], + "metadata": { + "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." + } + }, + "backupPolicyContinuousTier": { "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], + "metadata": { + "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." + } + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." + } + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, "metadata": { - "description": "Required. The value of the key-value." + "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." } }, - "appConfigurationName": { + "backupStorageRedundancy": { "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], + "metadata": { + "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." + } + }, + "networkRestrictions": { + "$ref": "#/definitions/networkRestrictionType", + "defaultValue": { + "ipRules": [], + "virtualNetworkRules": [], + "publicNetworkAccess": "Disabled" + }, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." } }, - "contentType": { + "minimumTlsVersion": { "type": "string", + "defaultValue": "Tls12", + "allowedValues": [ + "Tls12" + ], + "metadata": { + "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." + } + }, + "enableBurstCapacity": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." + } + }, + "enableCassandraConnector": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." + } + }, + "enablePartitionMerge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." + } + }, + "enablePerRegionPerPartitionAutoscale": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." + } + }, + "analyticalStorageConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" + }, + "description": "Optional. Analytical storage specific properties." + }, + "nullable": true + }, + "cors": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" + }, + "description": "Optional. The CORS policy for the Cosmos DB database account." + }, + "nullable": true + }, + "defaultIdentity": { + "$ref": "#/definitions/defaultIdentityType", + "defaultValue": { + "name": "FirstPartyIdentity" + }, + "metadata": { + "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", "nullable": true, "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInControlPlaneRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "appConfiguration": { - "existing": true, - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" + "cMKKeyVault": { + "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" + }, + "databaseAccount": { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", + "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", + "dependsOn": [ + "cMKKeyVault::cMKKey" + ] + }, + "databaseAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_diagnosticSettings": { + "copy": { + "name": "databaseAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_roleAssignments": { + "copy": { + "name": "databaseAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlDatabases": { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "3972888645334640168" + }, + "name": "DocumentDB Database Account SQL Databases", + "description": "This module deploys a SQL Database in a CosmosDB Account." + }, + "definitions": { + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a container." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "container": { + "copy": { + "name": "container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "conflictResolutionPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + }, + "defaultTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "kind": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + }, + "paths": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + }, + "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", + "uniqueKeyPolicyKeys": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "4781880351108045502" + }, + "name": "DocumentDB Database Account SQL Database Containers", + "description": "This module deploys a SQL Database Container in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "variables": { + "copy": [ + { + "name": "partitionKeyPaths", + "count": "[length(parameters('paths'))]", + "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + } + ] + }, + "resources": { + "databaseAccount::sqlDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "container": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlRoleDefinitions": { + "copy": { + "name": "databaseAccount_sqlRoleDefinitions", + "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "dataActions": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" + }, + "roleName": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "sqlRoleAssignments": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "8514367433037227852" + }, + "name": "DocumentDB Database Account SQL Role Definitions.", + "description": "This module deploys a SQL Role Definision in a CosmosDB Account." + }, + "definitions": { + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SQL Role Assignments." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionIdOrName": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The role name of the SQL Role Definition." + }, + "value": "[reference('sqlRoleDefinition').roleName]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key values." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionIdOrName": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[parameters('name')]" + "dependsOn": [ + "databaseAccount", + "databaseAccount_sqlDatabases", + "databaseAccount_sqlRoleDefinitions" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key values." + "databaseAccount_cassandraRoleDefinitions": { + "copy": { + "name": "databaseAccount_cassandraRoleDefinitions", + "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the batch account was deployed into." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "roleName": { + "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "dataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" + }, + "notDataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "cassandraRoleAssignments": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10787709019875067397" + }, + "name": "DocumentDB Database Account Cassandra Role Definitions.", + "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." + }, + "definitions": { + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]", + "notDataActions": "[parameters('notDataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cassandra role definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cassandra role definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the cassandra role definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" - }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", - "metadata": { - "description": "Optional. Name of the replica." - } - }, - "appConfigurationName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } + "dependsOn": [ + "databaseAccount" + ] }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - } - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration was deployed into." + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the replica that was deployed." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[parameters('name')]" + "dependsOn": [ + "databaseAccount", + "databaseAccount_cassandraKeyspaces", + "databaseAccount_cassandraRoleDefinitions" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the replica that was deployed." + "databaseAccount_mongodbDatabases": { + "copy": { + "name": "databaseAccount_mongodbDatabases", + "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "collections": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" }, + "throughput": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "autoscaleSettings": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "13897098552792121791" + }, + "name": "DocumentDB Database Account MongoDB Databases", + "description": "This module deploys a MongoDB Database within a CosmosDB Account." + }, + "definitions": { + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a collection." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "mongodbDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "mongodbDatabase_collections": { + "copy": { + "name": "mongodbDatabase_collections", + "count": "[length(coalesce(parameters('collections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "mongodbDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + }, + "indexes": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + }, + "shardKey": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "16151461445994734468" + }, + "name": "DocumentDB Database Account MongoDB Database Collections", + "description": "This module deploys a MongoDB Database Collection." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "mongodbDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]", + "indexes": "[parameters('indexes')]", + "shardKey": "[parameters('shardKey')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database collection." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database collection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "mongodbDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database was created in." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "__bicep_export!": true - } + "dependsOn": [ + "databaseAccount" + ] }, - "ipConfigurationType": { - "type": "object", + "databaseAccount_gremlinDatabases": { + "copy": { + "name": "databaseAccount_gremlinDatabases", + "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "graphs": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" } }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11959636451300474346" + }, + "name": "DocumentDB Database Account Gremlin Databases", + "description": "This module deploys a Gremlin Database within a CosmosDB Account." + }, + "definitions": { + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + "__bicep_export!": true, + "description": "The type of a graph." } - }, - "memberName": { + } + }, + "parameters": { + "name": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + "description": "Required. Name of the Gremlin database." } }, - "privateIPAddress": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "databaseAccountName": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { + }, + "graphs": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/graphType" }, + "nullable": true, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + "description": "Optional. Array of graphs to deploy in the Gremlin database." } }, - "privateLinkServiceId": { - "type": "string", + "maxThroughput": { + "type": "int", + "defaultValue": 4000, "metadata": { - "description": "Required. The resource id of private link service." + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." } }, - "requestMessage": { - "type": "string", + "throughput": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." } } }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "gremlinDatabase_gremlinGraphs": { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(coalesce(parameters('graphs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "partitionKeyPaths": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10487122333182352122" + }, + "name": "DocumentDB Database Accounts Gremlin Databases Graphs", + "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount::gremlinDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinGraph": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": "[parameters('indexingPolicy')]", + "partitionKey": { + "paths": "[parameters('partitionKeyPaths')]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "gremlinDatabase" + ] + } }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_tables": { + "copy": { + "name": "databaseAccount_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1787500858429182824" + }, + "name": "Azure Cosmos DB account tables", + "description": "This module deploys a table within an Azure Cosmos DB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "table": { + "type": "Microsoft.DocumentDB/databaseAccounts/tables", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" } } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" }, "dependsOn": [ - "privateEndpoint" + "databaseAccount" ] }, - "privateEndpoint_roleAssignments": { + "databaseAccount_cassandraKeyspaces": { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "name": "databaseAccount_cassandraKeyspaces", + "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" }, - "privateEndpointName": { - "value": "[parameters('name')]" + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "tables": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" + }, + "views": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" } }, "template": { @@ -63346,110 +67004,570 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "version": "0.40.2.10011", + "templateHash": "15257396763463366586" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "DocumentDB Database Account Cassandra Keyspaces", + "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." }, "definitions": { - "privateDnsZoneGroupConfigType": { + "tableType": { "type": "object", "properties": { "name": { "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." } }, - "privateDnsZoneResourceId": { + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra table." + } + }, + "viewType": { + "type": "object", + "properties": { + "name": { "type": "string", "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type of a Cassandra view (materialized view)." } } }, "parameters": { - "privateEndpointName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. Name of the Cassandra keyspace." } }, - "privateDnsZoneConfigs": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "tables": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "$ref": "#/definitions/tableType" }, - "minLength": 1, - "maxLength": 5, + "defaultValue": [], "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." } }, - "name": { - "type": "string", - "defaultValue": "default", + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/viewType" + }, + "defaultValue": [], "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraKeyspace": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "cassandraKeyspace_tables": { + "copy": { + "name": "cassandraKeyspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "schema": { + "value": "[parameters('tables')[copyIndex()].schema]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + }, + "throughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "defaultTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15998065591386988132" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Tables", + "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra table resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the Cassandra table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "defaultTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraTable": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "schema": "[parameters('schema')]", + "defaultTtl": "[parameters('defaultTtl')]", + "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + }, + "cassandraKeyspace_views": { + "copy": { + "name": "cassandraKeyspace_views", + "count": "[length(parameters('views'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('views')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "viewDefinition": { + "value": "[parameters('views')[copyIndex()].viewDefinition]" + }, + "throughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6617803098467821091" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Views", + "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra view." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags of the Cassandra view resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraView": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "viewDefinition": "[parameters('viewDefinition')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra view." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra view." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra view was created in." + }, + "value": "[resourceGroup().name]" + } } } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } + }, + "dependsOn": [ + "cassandraKeyspace" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the Cassandra keyspace." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the Cassandra keyspace." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The name of the resource group the Cassandra keyspace was created in." }, "value": "[resourceGroup().name]" } @@ -63457,1228 +67575,1118 @@ } }, "dependsOn": [ - "privateEndpoint" + "databaseAccount" ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." + "databaseAccount_privateEndpoints": { + "copy": { + "name": "databaseAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the app configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the app configuration." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration store was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the app configuration." - }, - "value": "[reference('configurationStore').endpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the app configuration." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "avmAppConfig", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", - "virtualNetwork" - ] - }, - "avmContainerApp_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the database account." + }, + "value": "[parameters('name')]" }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the database account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the database account was created in." + }, + "value": "[resourceGroup().name]" }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the database account." + }, + "value": "[reference('databaseAccount').documentEndpoint]" }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + }, + "primaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" + }, + "primaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" + }, + "primaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" + }, + "primaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" + }, + "secondaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" + }, + "secondaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" + }, + "secondaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" + }, + "secondaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" + } + } + } } - }, - "clientCertificateMode": { + } + }, + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } + "description": "Resource ID of the Cosmos DB account." + }, + "value": "[reference('cosmosAccount').outputs.resourceId.value]" }, - "stickySessionsAffinity": { + "name": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } + "description": "Name of the Cosmos DB account." + }, + "value": "[reference('cosmosAccount').outputs.name.value]" }, - "ingressTransport": { + "connectionString": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." + "description": "MongoDB connection string (without credentials — use Key Vault for secrets)." }, - "nullable": true + "value": "[format('mongodb+srv://{0}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000', parameters('name'))]" }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, + "primaryReadWriteConnectionString": { + "type": "string", "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" + "description": "Primary read-write connection string from the Cosmos DB account." }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } + "value": "[listOutputsWithSecureValues('cosmosAccount', '2025-04-01').primaryReadWriteConnectionString]" }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, + "endpoint": { + "type": "string", "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } + "description": "Endpoint of the Cosmos DB account." + }, + "value": "[format('https://{0}.mongo.cosmos.azure.com:443/', parameters('name'))]" }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, + "databaseName": { + "type": "string", "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 + "description": "Database name." }, - "metadata": { - "description": "Optional. The scaling settings of the service." + "value": "[parameters('databaseName')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cosmosDB), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('location')]" + } + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "sku": { + "value": "Standard" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "disableLocalAuth": { + "value": false + }, + "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" + ] + }, + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_PROCESS", + "value": "Processes" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMA", + "value": "Schemas" + }, + { + "name": "APP_COSMOS_DATABASE", + "value": "ContentProcess" + }, + { + "name": "APP_CPS_CONFIGURATION", + "value": "cps-configuration" + }, + { + "name": "APP_CPS_MAX_FILESIZE_MB", + "value": "20" + }, + { + "name": "APP_CPS_PROCESSES", + "value": "cps-processes" + }, + { + "name": "APP_MESSAGE_QUEUE_EXTRACT", + "value": "content-pipeline-extract-queue" + }, + { + "name": "APP_MESSAGE_QUEUE_INTERVAL", + "value": "5" + }, + { + "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", + "value": "180" + }, + { + "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", + "value": "10" + }, + { + "name": "APP_PROCESS_STEPS", + "value": "extract,map,evaluate,save" + }, + { + "name": "APP_STORAGE_BLOB_URL", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.blob]" + }, + { + "name": "APP_STORAGE_QUEUE_URL", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[coalesce(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" + }, + { + "name": "APP_COSMOS_CONNSTR", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.primaryReadWriteConnectionString.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", + "value": "claimprocesses" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCHES", + "value": "batches" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMASET", + "value": "Schemasets" + }, + { + "name": "APP_CPS_PROCESS_BATCH", + "value": "process-batch" + }, + { + "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", + "value": "[format('http://{0}/', reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value)]" + }, + { + "name": "APP_CPS_POLL_INTERVAL_SECONDS", + "value": "3" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "CLAIM_PROCESS_QUEUE_NAME", + "value": "claim-process-queue" + }, + { + "name": "DEAD_LETTER_QUEUE_NAME", + "value": "claim-process-dead-letter-queue" + }, + { + "name": "AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", + "value": "[parameters('gptModelName')]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_OPENAI_ENDPOINT_BASE", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", + "value": "" + }, + { + "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", + "value": "" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + }, + { + "name": "GLOBAL_LLM_SERVICE", + "value": "AzureOpenAI" + }, + { + "name": "GPT5_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "GPT5_CHAT_DEPLOYMENT_NAME", + "value": "gpt-5" + }, + { + "name": "GPT5_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "PHI4_API_VERSION", + "value": "2024-05-01-preview" + }, + { + "name": "PHI4_CHAT_DEPLOYMENT_NAME", + "value": "phi-4" + }, + { + "name": "PHI4_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" } - }, - "activeRevisionsMode": { + ] + }, + "publicNetworkAccess": { + "value": "Enabled" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8501097744482672663" + } + }, + "parameters": { + "name": { "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + "description": "Name of the App Configuration store." } }, - "environmentResourceId": { + "location": { "type": "string", "metadata": { - "description": "Required. Resource ID of environment." + "description": "Azure region for the resource." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Whether purge protection is enabled." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Tags to apply to the resource." } }, "enableTelemetry": { @@ -64688,334 +68696,122 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { + "managedIdentities": { "type": "object", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." + "description": "Managed identity configuration." } }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", + "sku": { + "type": "string", + "defaultValue": "Standard", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." + "description": "SKU for the App Configuration store." } }, - "terminationGracePeriodSeconds": { - "type": "int", + "diagnosticSettings": { + "type": "array", "nullable": true, "metadata": { - "description": "Optional. The termination grace period for the container app." + "description": "Optional. Diagnostic settings to apply to the App Configuration store." } }, - "initContainersTemplate": { - "type": "array", + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true + "description": "Whether local authentication is disabled." + } }, - "secrets": { + "replicaLocations": { "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The secrets of the Container App." + "description": "Optional. Replica locations for the App Configuration store." } }, - "revisionSuffix": { - "type": "string", - "nullable": true, + "roleAssignments": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "Role assignments for the App Configuration store." } }, - "volumes": { + "keyValues": { "type": "array", + "defaultValue": [], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." + "description": "Key-values to create in the App Configuration store." } }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. The name of the Container App Auth configs." + "description": "Public network access setting." } }, - "diagnosticSettings": { + "privateEndpoints": { "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Private endpoint configuration." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + "appConfiguration": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.app-configuration.configuration-store.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { + "name": { "value": "[parameters('name')]" }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "replicaLocations": { + "value": "[parameters('replicaLocations')]" }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "roleAssignments": { + "value": "[parameters('roleAssignments')]" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "keyValues": { + "value": "[parameters('keyValues')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" } }, "template": { @@ -65025,1697 +68821,2432 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { - "type": "string", + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } } }, - "encryptionSettings": { + "managedIdentityAllType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "nullable": true - }, - "globalValidation": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "httpSettings": { + "privateEndpointSingleServiceType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } - } - } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" - ] - }, - "avmContainerApp_API_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 - } - ] - } - ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" - } - } - } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the app configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the app configuration." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration store was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the app configuration." + }, + "value": "[reference('configurationStore').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the app configuration." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." - } + "description": "Resource ID of the App Configuration store." + }, + "value": "[reference('appConfiguration').outputs.resourceId.value]" }, - "kind": { + "name": { "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } + "description": "Name of the App Configuration store." + }, + "value": "[reference('appConfiguration').outputs.name.value]" }, - "clientCertificateMode": { + "endpoint": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, "metadata": { - "description": "Optional. Object userd to configure CORS policy." + "description": "Endpoint of the App Configuration store." + }, + "value": "[reference('appConfiguration').outputs.endpoint.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-configuration.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "privateEndpoints": { + "value": [ + { + "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", + "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "name": "appconfig-dns-zone-group", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').appConfig), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + }, + "subnetResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value]" } - }, - "stickySessionsAffinity": { + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8501097744482672663" + } + }, + "parameters": { + "name": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." + "description": "Name of the App Configuration store." } }, - "ingressTransport": { + "location": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], "metadata": { - "description": "Optional. Ingress transport protocol." + "description": "Azure region for the resource." } }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { + "enablePurgeProtection": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Toggle to include the service configuration." + "description": "Whether purge protection is enabled." } }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. Settings to expose additional ports on container app." + "description": "Tags to apply to the resource." } }, - "ingressAllowInsecure": { + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, + "managedIdentities": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + "description": "Managed identity configuration." } }, - "environmentResourceId": { + "sku": { "type": "string", + "defaultValue": "Standard", "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "SKU for the App Configuration store." } }, - "roleAssignments": { + "diagnosticSettings": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Diagnostic settings to apply to the App Configuration store." } }, - "enableTelemetry": { + "disableLocalAuth": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, + "defaultValue": false, "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + "description": "Whether local authentication is disabled." } }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { + "replicaLocations": { "type": "array", + "defaultValue": [], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." + "description": "Optional. Replica locations for the App Configuration store." } }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { + "roleAssignments": { "type": "array", + "defaultValue": [], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." + "description": "Role assignments for the App Configuration store." } }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { + "keyValues": { "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "Key-values to create in the App Configuration store." } }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { + "publicNetworkAccess": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, + "defaultValue": "Enabled", "metadata": { - "description": "Optional. The name of the Container App Auth configs." + "description": "Public network access setting." } }, - "diagnosticSettings": { + "privateEndpoints": { "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Private endpoint configuration." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + "appConfiguration": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.app-configuration.configuration-store.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { + "name": { "value": "[parameters('name')]" }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "replicaLocations": { + "value": "[parameters('replicaLocations')]" }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "roleAssignments": { + "value": "[parameters('roleAssignments')]" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "keyValues": { + "value": "[parameters('keyValues')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" } }, "template": { @@ -66725,1923 +71256,2297 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" + "version": "0.37.4.10188", + "templateHash": "396653159019145335" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." }, - "parameters": { - "containerAppName": { - "type": "string", + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for the data plane proxy." } }, - "encryptionSettings": { + "privateEndpointOutputType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } }, - "globalValidation": { + "replicaLocationType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } }, - "nullable": true + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } }, - "httpSettings": { + "_1.lockType": { "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "identityProviders": { + "_1.privateEndpointIpConfigurationType": { "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "login": { + "_1.roleAssignmentType": { "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } }, - "nullable": true + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "platform": { + "diagnosticSettingFullType": { "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "managedIdentityAllType": { + "type": "object", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "value": "current" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" - ] - }, - "avmContainerApp_Workflow_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." }, - "parameters": { - "containerAppName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." - } - }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "description": "The name of the app configuration." }, - "nullable": true + "value": "[parameters('name')]" }, - "identityProviders": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "description": "The resource ID of the app configuration." }, - "nullable": true + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" }, - "login": { - "type": "object", + "resourceGroupName": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "description": "The resource group the app configuration store was deployed into." }, - "nullable": true + "value": "[resourceGroup().name]" }, - "platform": { - "type": "object", + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "The principal ID of the system assigned identity." }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { + "location": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "The location the resource was deployed into." }, - "value": "current" + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" }, - "resourceId": { + "endpoint": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "The endpoint of the app configuration." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference('configurationStore').endpoint]" }, - "resourceGroupName": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "The private endpoints of the app configuration." }, - "value": "[resourceGroup().name]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } - }, - "dependsOn": [ - "containerApp" - ] + } } }, "outputs": { "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." + "description": "Resource ID of the App Configuration store." }, - "value": "[resourceGroup().name]" + "value": "[reference('appConfiguration').outputs.resourceId.value]" }, "name": { "type": "string", "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "Name of the App Configuration store." }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + "value": "[reference('appConfiguration').outputs.name.value]" }, - "location": { + "endpoint": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "Endpoint of the App Configuration store." }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[reference('appConfiguration').outputs.endpoint.value]" } } } }, "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').appConfig), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" ] } - }, + ], "outputs": { "CONTAINER_WEB_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for Web App." }, - "value": "[reference('avmContainerApp_Web').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_API_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for API." }, - "value": "[reference('avmContainerApp_API').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WEB_APP_FQDN": { "type": "string", "metadata": { "description": "The FQDN of the Container App." }, - "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.fqdn.value]" }, "CONTAINER_API_APP_FQDN": { "type": "string", "metadata": { "description": "The FQDN of the Container App API." }, - "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.fqdn.value]" }, "CONTAINER_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for APP." }, - "value": "[reference('avmContainerApp').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for Workflow." }, - "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_APP_USER_IDENTITY_ID": { "type": "string", "metadata": { "description": "The user identity resource ID used fot the Container APP." }, - "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, "CONTAINER_APP_USER_PRINCIPAL_ID": { "type": "string", "metadata": { "description": "The user identity Principal ID used fot the Container APP." }, - "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" }, "CONTAINER_REGISTRY_NAME": { "type": "string", "metadata": { "description": "The name of the Azure Container Registry." }, - "value": "[reference('avmContainerRegistry').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_REGISTRY_LOGIN_SERVER": { "type": "string", "metadata": { "description": "The login server of the Azure Container Registry." }, - "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" }, "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { "type": "string", "metadata": { "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." }, - "value": "[reference('avmAiServices').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "AZURE_RESOURCE_GROUP": { "type": "string", diff --git a/infra/avm/modules/ai/ai-foundry-connection.bicep b/infra/avm/modules/ai/ai-foundry-connection.bicep index c3260e4d..443de377 100644 --- a/infra/avm/modules/ai/ai-foundry-connection.bicep +++ b/infra/avm/modules/ai/ai-foundry-connection.bicep @@ -38,6 +38,9 @@ param isDefault bool = false @description('Optional. Connection metadata object.') param metadata object = {} +@description('Optional. Whether to use workspace-managed identity for authentication.') +param useWorkspaceManagedIdentity bool = false + @secure() @description('Optional. Credentials key (for ApiKey auth type).') param credentialsKey string = '' @@ -63,6 +66,7 @@ var baseProperties = { authType: authType isSharedToAll: isSharedToAll metadata: metadata + useWorkspaceManagedIdentity: useWorkspaceManagedIdentity } var optionalDefault = isDefault ? { isDefault: true } : {} diff --git a/infra/avm/modules/ai/ai-foundry-project.bicep b/infra/avm/modules/ai/ai-foundry-project.bicep index 76671e96..9067006c 100644 --- a/infra/avm/modules/ai/ai-foundry-project.bicep +++ b/infra/avm/modules/ai/ai-foundry-project.bicep @@ -88,13 +88,13 @@ module aiServicesAccount 'br/public:avm/res/cognitive-services/account:0.14.2' = // ============================================================================ // AI Foundry Project // ============================================================================ -resource aiServicesResource 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { name: name dependsOn: [aiServicesAccount] } resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { - parent: aiServicesResource + parent: aiServices name: projectName location: location tags: tags @@ -111,16 +111,19 @@ resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = // ============================================================================ @description('Resource ID of the AI Services account.') -output resourceId string = aiServicesAccount.outputs.resourceId +output resourceId string = aiServices.id @description('Name of the AI Services account.') -output name string = aiServicesAccount.outputs.name +output name string = aiServices.name -@description('Endpoint of the AI Services account.') -output endpoint string = aiServicesAccount.outputs.endpoint +@description('Endpoint of the AI Services account (OpenAI Language Model Instance API).') +output endpoint string = aiServices.properties.endpoints['OpenAI Language Model Instance API'] + +@description('Azure OpenAI Content Understanding endpoint URL.') +output azureOpenAiCuEndpoint string = aiServices.properties.endpoints['Content Understanding'] @description('System-assigned identity principal ID of the AI Services account.') -output principalId string = aiServicesAccount.outputs.systemAssignedMIPrincipalId +output principalId string = aiServices.identity.principalId @description('Resource ID of the AI Foundry project.') output projectResourceId string = aiProject.id diff --git a/infra/avm/modules/ai/ai-foundry.bicep b/infra/avm/modules/ai/ai-foundry.bicep index 4342f5f9..e187bcdc 100644 --- a/infra/avm/modules/ai/ai-foundry.bicep +++ b/infra/avm/modules/ai/ai-foundry.bicep @@ -95,6 +95,12 @@ import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7 @description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType[]? +@description('Optional. Principal ID of the processor container app managed identity.') +param processorPrincipalId string = '' + +@description('Optional. Principal ID of the workflow container app managed identity.') +param workflowPrincipalId string = '' + @description('Optional. Tags of the resource.') param tags object? @@ -137,6 +143,18 @@ param enableTelemetry bool = true @description('Optional. Array of deployments about cognitive service accounts to create.') param deployments deploymentType[]? +@description('Optional. GPT model name used to build the default deployment.') +param gptModelName string = '' + +@description('Optional. GPT model version used to build the default deployment.') +param gptModelVersion string = '' + +@description('Optional. Deployment SKU name for the default GPT deployment.') +param gptDeploymentSkuName string = '' + +@description('Optional. Deployment capacity for the default GPT deployment.') +param gptDeploymentCapacity int = -1 + @description('Optional. Key vault reference and secret settings for the module\'s secrets export.') param secretsExportConfiguration secretsExportConfigurationType? @@ -149,6 +167,74 @@ var formattedUserAssignedIdentities = reduce( (cur, next) => union(cur, next) ) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } +var resolvedRoleAssignments = !empty(roleAssignments ?? []) + ? roleAssignments + : concat( + !empty(processorPrincipalId) + ? [ + { + principalId: processorPrincipalId + roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' + principalType: 'ServicePrincipal' + } + { + principalId: processorPrincipalId + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' + } + { + principalId: processorPrincipalId + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' + } + { + principalId: processorPrincipalId + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' + } + ] + : [], + !empty(workflowPrincipalId) + ? [ + { + principalId: workflowPrincipalId + roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + principalType: 'ServicePrincipal' + } + { + principalId: workflowPrincipalId + roleDefinitionIdOrName: 'Azure AI Developer' + principalType: 'ServicePrincipal' + } + { + principalId: workflowPrincipalId + roleDefinitionIdOrName: 'Cognitive Services User' + principalType: 'ServicePrincipal' + } + ] + : [] + ) + +var resolvedDeployments = !empty(deployments ?? []) + ? deployments + : (!empty(gptModelName) && !empty(gptModelVersion) && !empty(gptDeploymentSkuName) && gptDeploymentCapacity > 0 + ? [ + { + name: gptModelName + model: { + format: 'OpenAI' + name: gptModelName + version: gptModelVersion + } + sku: { + name: gptDeploymentSkuName + capacity: gptDeploymentCapacity + } + raiPolicyName: 'Microsoft.Default' + } + ] + : []) + var identity = !empty(managedIdentities) ? { type: (managedIdentities.?systemAssigned ?? false) @@ -260,11 +346,11 @@ module cognitive_service_dependencies './modules/dependencies.bicep' = if(!useEx projectDescription: projectDescription name: cognitiveServiceNew.name location: location - deployments: deployments + deployments: resolvedDeployments diagnosticSettings: diagnosticSettings lock: lock privateEndpoints: privateEndpoints - roleAssignments: roleAssignments + roleAssignments: resolvedRoleAssignments secretsExportConfiguration: secretsExportConfiguration sku: sku tags: tags @@ -278,11 +364,11 @@ module existing_cognitive_service_dependencies './modules/dependencies.bicep' = projectDescription: projectDescription azureExistingAIProjectResourceId: existingFoundryProjectResourceId location: location - deployments: deployments + deployments: resolvedDeployments diagnosticSettings: diagnosticSettings lock: lock privateEndpoints: privateEndpoints - roleAssignments: roleAssignments + roleAssignments: resolvedRoleAssignments secretsExportConfiguration: secretsExportConfiguration sku: sku tags: tags diff --git a/infra/avm/modules/ai/existing-project-setup.bicep b/infra/avm/modules/ai/existing-project-setup.bicep index 7a396dcb..efdc5753 100644 --- a/infra/avm/modules/ai/existing-project-setup.bicep +++ b/infra/avm/modules/ai/existing-project-setup.bicep @@ -15,36 +15,43 @@ param projectName string // ============================================================================ // Existing Resource References // ============================================================================ -resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { name: name } resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' existing = { - parent: cognitiveService + parent: aiServices name: projectName } // ============================================================================ -// Outputs +// Outputs (aligned with ai-foundry-project.bicep) // ============================================================================ -@description('The principal ID of the AI Foundry system-assigned managed identity (empty if none).') -output aiFoundryPrincipalId string = cognitiveService.identity.?principalId ?? '' -@description('The principal ID of the AI Project system-assigned managed identity (empty if none).') -output aiProjectPrincipalId string = aiProject.identity.?principalId ?? '' +@description('Resource ID of the AI Services account.') +output resourceId string = aiServices.id -@description('The name of the AI Services account.') -output aiServicesAccountName string = cognitiveService.name +@description('Name of the AI Services account.') +output name string = aiServices.name -@description('The name of the AI project.') -output aiProjectName string = aiProject.name +@description('Endpoint of the AI Services account (OpenAI Language Model Instance API).') +output endpoint string = aiServices.properties.endpoints['OpenAI Language Model Instance API'] -@description('The endpoint URL for the Azure OpenAI service.') -output aiFoundryEndpoint string = 'https://${name}.openai.azure.com/' +@description('Azure OpenAI Content Understanding endpoint URL.') +output azureOpenAiCuEndpoint string = aiServices.properties.endpoints['Content Understanding'] -@description('The endpoint URL for the AI Foundry project.') -output projectEndpoint string = 'https://${name}.services.ai.azure.com/api/projects/${projectName}' +@description('System-assigned identity principal ID of the AI Services account (empty if none).') +output principalId string = aiServices.identity.?principalId ?? '' -@description('The resource ID of the AI Services account.') -output aiFoundryResourceId string = cognitiveService.id +@description('Resource ID of the AI Foundry project.') +output projectResourceId string = aiProject.id + +@description('Name of the AI Foundry project.') +output projectName string = aiProject.name + +@description('AI Foundry project endpoint.') +output projectEndpoint string = aiProject.properties.endpoints['AI Foundry API'] + +@description('System-assigned identity principal ID of the project (empty if none).') +output projectIdentityPrincipalId string = aiProject.identity.?principalId ?? '' diff --git a/infra/avm/modules/compute/container-app-api.bicep b/infra/avm/modules/compute/container-app-api.bicep new file mode 100644 index 00000000..d32d1828 --- /dev/null +++ b/infra/avm/modules/compute/container-app-api.bicep @@ -0,0 +1,177 @@ +@description('Unique solution suffix used to derive resource names.') +param solutionSuffix string + +@description('Azure region for the resource.') +param location string + +@description('Resource ID of the container app environment.') +param environmentResourceId string + +@description('Container registry endpoint hosting the API image.') +param containerRegistryEndpoint string + +@description('Image tag to deploy.') +param imageTag string + +@description('Whether additional scale-out should be enabled.') +param enableScalability bool + +@description('Whether monitoring is enabled.') +param enableMonitoring bool = false + +@description('Optional. Application Insights connection string.') +param appInsightsConnectionString string = '' + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('User-assigned managed identity resource IDs to attach to the container app.') +param userAssignedResourceIds array = [] + +@description('Optional. App Configuration endpoint for post-bootstrap updates.') +param appConfigEndpoint string = '' + +var containerAppName = 'ca-${solutionSuffix}-api' +var scaleSettings = { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] +} +var corsPolicy = { + allowedOrigins: [ + '*' + ] + allowedMethods: [ + 'GET' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + ] + allowedHeaders: [ + 'Authorization' + 'Content-Type' + '*' + ] +} + +module containerApp './container-app.bicep' = { + name: take('module.container-app-api.${solutionSuffix}', 64) + params: { + name: containerAppName + location: location + environmentResourceId: environmentResourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: userAssignedResourceIds + } + containers: [ + { + name: containerAppName + image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: appConfigEndpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? appInsightsConnectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorAPI' + } + ] + probes: [ + { + type: 'Liveness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Readiness' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + } + { + type: 'Startup' + httpGet: { + path: '/startup' + port: 80 + scheme: 'HTTP' + } + initialDelaySeconds: 20 + periodSeconds: 5 + failureThreshold: 10 + } + ] + } + ] + scaleSettings: scaleSettings + ingressExternal: true + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + corsPolicy: corsPolicy + } +} + +@description('Resource ID of the container app.') +output resourceId string = containerApp.outputs.resourceId + +@description('Name of the container app.') +output name string = containerApp.outputs.name + +@description('Fully qualified domain name of the container app.') +output fqdn string = containerApp.outputs.fqdn + +@description('Principal ID of the system-assigned managed identity.') +output systemAssignedMIPrincipalId string? = containerApp.outputs.?systemAssignedMIPrincipalId diff --git a/infra/avm/modules/compute/container-app-environment.bicep b/infra/avm/modules/compute/container-app-environment.bicep index 1f488eed..03478bb5 100644 --- a/infra/avm/modules/compute/container-app-environment.bicep +++ b/infra/avm/modules/compute/container-app-environment.bicep @@ -1,95 +1,65 @@ // ============================================================================ -// Module: Azure Container Apps Environment (AVM) -// AVM Module: avm/res/app/managed-environment:0.13.3 +// Module: Container App Environment +// Description: AVM wrapper for Azure Container Apps managed environment +// AVM Module: avm/res/app/managed-environment:0.13.2 // ============================================================================ -@description('Solution name used for naming convention.') -param solutionName string +@description('Name of the container app environment.') +param name string -@description('Name of the Container Apps Environment.') -param name string = 'cae-${solutionName}' - -@description('Azure region for deployment.') +@description('Azure region for the resource.') param location string -@description('Resource tags.') +@description('Tags to apply to the resource.') param tags object = {} -@description('Resource ID of the Log Analytics workspace (required when enableMonitoring is true).') -param logAnalyticsWorkspaceResourceId string = '' +@description('Managed identity configuration.') +param managedIdentities object -@description('Subnet resource ID for VNet integration (required when enablePrivateNetworking is true).') -param infrastructureSubnetId string = '' +@description('Optional. Application logs configuration.') +param appLogsConfiguration object? -@description('Enable zone redundancy.') -param zoneRedundant bool = false +@description('Workload profiles for the environment.') +param workloadProfiles array -@description('Enable Azure telemetry collection.') +@description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -@description('Enable private networking (internal environment, public access disabled).') -param enablePrivateNetworking bool = false +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' -@description('Enable monitoring (Log Analytics + App Insights).') -param enableMonitoring bool = true +@description('Optional. Platform reserved CIDR block.') +param platformReservedCidr string = '' -@description('Application Insights connection string (optional, for App Insights integration).') -param appInsightsConnectionString string = '' +@description('Optional. Platform reserved DNS IP.') +param platformReservedDnsIP string = '' -@description('Enable redundancy (dedicated workload profiles + infra resource group).') -param enableRedundancy bool = false +@description('Whether the environment is zone redundant.') +param zoneRedundant bool = false -@description('Infrastructure resource group name (used when zone redundancy is enabled). Defaults to "{resourceGroup}-infra" if empty.') -param infrastructureResourceGroupName string = '${resourceGroup().name}-infra' +@description('Optional. Infrastructure subnet resource ID.') +param infrastructureSubnetResourceId string = '' -@description('Workload profiles configuration (e.g., Consumption or dedicated D4 profiles).') -param workloadProfiles array = [ - { - name: 'Consumption' - workloadProfileType: 'Consumption' - } -] - -// ============================================================================ -// Container Apps Environment (AVM) -// ============================================================================ -module managedEnvironment 'br/public:avm/res/app/managed-environment:0.13.3' = { - name: take('avm.res.app.managedenvironment.${name}', 64) +module containerAppEnvironment 'br/public:avm/res/app/managed-environment:0.13.2' = { + name: take('avm.res.app.managed-environment.${name}', 64) params: { name: name location: location tags: tags - enableTelemetry: enableTelemetry - // WAF: Private networking - publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' - internal: enablePrivateNetworking - infrastructureSubnetResourceId: !empty(infrastructureSubnetId) ? infrastructureSubnetId : null - // WAF: Monitoring - appLogsConfiguration: enableMonitoring && !empty(logAnalyticsWorkspaceResourceId) - ? { - destination: 'log-analytics' - logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId - } - : null - appInsightsConnectionString: !empty(appInsightsConnectionString) ? appInsightsConnectionString : null - // WAF: Redundancy - zoneRedundant: zoneRedundant || enableRedundancy - infrastructureResourceGroupName: !empty(infrastructureResourceGroupName) ? infrastructureResourceGroupName : null + managedIdentities: managedIdentities + appLogsConfiguration: appLogsConfiguration workloadProfiles: workloadProfiles + enableTelemetry: enableTelemetry + publicNetworkAccess: publicNetworkAccess + platformReservedCidr: !empty(platformReservedCidr) ? platformReservedCidr : null + platformReservedDnsIP: !empty(platformReservedDnsIP) ? platformReservedDnsIP : null + zoneRedundant: zoneRedundant + infrastructureSubnetResourceId: !empty(infrastructureSubnetResourceId) ? infrastructureSubnetResourceId : null } } -// ============================================================================ -// Outputs -// ============================================================================ -@description('The name of the Container Apps Environment.') -output name string = managedEnvironment.outputs.name - -@description('The resource ID of the Container Apps Environment.') -output resourceId string = managedEnvironment.outputs.resourceId - -@description('The default domain of the Container Apps Environment.') -output defaultDomain string = managedEnvironment.outputs.defaultDomain +@description('Resource ID of the container app environment.') +output resourceId string = containerAppEnvironment.outputs.resourceId -@description('The static IP of the Container Apps Environment.') -output staticIp string = managedEnvironment.outputs.staticIp +@description('Name of the container app environment.') +output name string = containerAppEnvironment.outputs.name diff --git a/infra/avm/modules/compute/container-app-processor.bicep b/infra/avm/modules/compute/container-app-processor.bicep new file mode 100644 index 00000000..0f1983c5 --- /dev/null +++ b/infra/avm/modules/compute/container-app-processor.bicep @@ -0,0 +1,131 @@ +@description('Unique solution suffix used to derive resource names.') +param solutionSuffix string + +@description('Azure region for the resource.') +param location string + +@description('Resource ID of the container app environment.') +param environmentResourceId string + +@description('Container registry endpoint hosting the processor image.') +param containerRegistryEndpoint string + +@description('Image tag to deploy.') +param imageTag string + +@description('Whether additional scale-out should be enabled.') +param enableScalability bool + +@description('Whether monitoring is enabled.') +param enableMonitoring bool = false + +@description('Optional. Application Insights connection string.') +param appInsightsConnectionString string = '' + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('User-assigned managed identity resource IDs to attach to the container app.') +param userAssignedResourceIds array = [] + +@description('Optional. App Configuration endpoint for post-bootstrap updates.') +param appConfigEndpoint string = '' + +var containerAppName = 'ca-${solutionSuffix}-app' +var containerName = 'ca-${solutionSuffix}' +var scaleSettings = empty(appConfigEndpoint) + ? { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + } + : { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: enableScalability + ? [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: 100 + } + } + } + ] + : [] + } + +module containerApp './container-app.bicep' = { + name: take('module.container-app-processor.${solutionSuffix}', 64) + params: { + name: containerAppName + location: location + environmentResourceId: environmentResourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: userAssignedResourceIds + } + containers: [ + { + name: containerName + image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: appConfigEndpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? appInsightsConnectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessor' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: scaleSettings + } +} + +@description('Resource ID of the container app.') +output resourceId string = containerApp.outputs.resourceId + +@description('Name of the container app.') +output name string = containerApp.outputs.name + +@description('Fully qualified domain name of the container app.') +output fqdn string = containerApp.outputs.fqdn + +@description('Principal ID of the system-assigned managed identity.') +output systemAssignedMIPrincipalId string? = containerApp.outputs.?systemAssignedMIPrincipalId diff --git a/infra/avm/modules/compute/container-app-web.bicep b/infra/avm/modules/compute/container-app-web.bicep new file mode 100644 index 00000000..457eb380 --- /dev/null +++ b/infra/avm/modules/compute/container-app-web.bicep @@ -0,0 +1,123 @@ +@description('Unique solution suffix used to derive resource names.') +param solutionSuffix string + +@description('Azure region for the resource.') +param location string + +@description('Resource ID of the container app environment.') +param environmentResourceId string + +@description('Container registry endpoint hosting the web image.') +param containerRegistryEndpoint string + +@description('Image tag to deploy.') +param imageTag string + +@description('Whether additional scale-out should be enabled.') +param enableScalability bool + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('User-assigned managed identity resource IDs to attach to the container app.') +param userAssignedResourceIds array = [] + +@description('API application FQDN used by the frontend.') +param apiAppFqdn string + +var containerAppName = 'ca-${solutionSuffix}-web' +var scaleSettings = { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: '100' + } + } + } + ] +} + +module containerApp './container-app.bicep' = { + name: take('module.container-app-web.${solutionSuffix}', 64) + params: { + name: containerAppName + location: location + environmentResourceId: environmentResourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: userAssignedResourceIds + } + ingressExternal: true + ingressTargetPort: 3000 + activeRevisionsMode: 'Single' + ingressTransport: 'auto' + ingressAllowInsecure: false + scaleSettings: scaleSettings + containers: [ + { + name: containerAppName + image: '${containerRegistryEndpoint}/contentprocessorweb:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_API_BASE_URL' + value: 'https://${apiAppFqdn}' + } + { + name: 'APP_WEB_CLIENT_ID' + value: '' + } + { + name: 'APP_WEB_AUTHORITY' + value: '${environment().authentication.loginEndpoint}/${tenant().tenantId}' + } + { + name: 'APP_WEB_SCOPE' + value: '' + } + { + name: 'APP_API_SCOPE' + value: '' + } + { + name: 'APP_REDIRECT_URL' + value: '/' + } + { + name: 'APP_POST_REDIRECT_URL' + value: '/' + } + { + name: 'APP_CONSOLE_LOG_ENABLED' + value: 'false' + } + ] + } + ] + } +} + +@description('Resource ID of the container app.') +output resourceId string = containerApp.outputs.resourceId + +@description('Name of the container app.') +output name string = containerApp.outputs.name + +@description('Fully qualified domain name of the container app.') +output fqdn string = containerApp.outputs.fqdn + +@description('Principal ID of the system-assigned managed identity.') +output systemAssignedMIPrincipalId string? = containerApp.outputs.?systemAssignedMIPrincipalId diff --git a/infra/avm/modules/compute/container-app-workflow.bicep b/infra/avm/modules/compute/container-app-workflow.bicep new file mode 100644 index 00000000..46cf09d1 --- /dev/null +++ b/infra/avm/modules/compute/container-app-workflow.bicep @@ -0,0 +1,113 @@ +@description('Unique solution suffix used to derive resource names.') +param solutionSuffix string + +@description('Azure region for the resource.') +param location string + +@description('Resource ID of the container app environment.') +param environmentResourceId string + +@description('Container registry endpoint hosting the workflow image.') +param containerRegistryEndpoint string + +@description('Image tag to deploy.') +param imageTag string + +@description('Whether additional scale-out should be enabled.') +param enableScalability bool + +@description('Whether monitoring is enabled.') +param enableMonitoring bool = false + +@description('Optional. Application Insights connection string.') +param appInsightsConnectionString string = '' + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('User-assigned managed identity resource IDs to attach to the container app.') +param userAssignedResourceIds array = [] + +@description('Optional. App Configuration endpoint for post-bootstrap updates.') +param appConfigEndpoint string = '' + +var containerAppName = 'ca-${solutionSuffix}-wkfl' +var scaleSettings = { + maxReplicas: enableScalability ? 3 : 2 + minReplicas: enableScalability ? 2 : 1 +} + +module containerApp './container-app.bicep' = { + name: take('module.container-app-workflow.${solutionSuffix}', 64) + params: { + name: containerAppName + location: location + environmentResourceId: environmentResourceId + workloadProfileName: 'Consumption' + enableTelemetry: enableTelemetry + tags: tags + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: userAssignedResourceIds + } + containers: [ + { + name: containerAppName + image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + resources: { + cpu: 4 + memory: '8.0Gi' + } + env: [ + { + name: 'APP_CONFIG_ENDPOINT' + value: appConfigEndpoint + } + { + name: 'APP_ENV' + value: 'prod' + } + { + name: 'APP_LOGGING_LEVEL' + value: 'INFO' + } + { + name: 'AZURE_PACKAGE_LOGGING_LEVEL' + value: 'WARNING' + } + { + name: 'AZURE_LOGGING_PACKAGES' + value: '' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: enableMonitoring ? appInsightsConnectionString : '' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'ContentProcessorWorkflow' + } + ] + } + ] + activeRevisionsMode: 'Single' + ingressExternal: false + disableIngress: true + scaleSettings: scaleSettings + } +} + +@description('Resource ID of the container app.') +output resourceId string = containerApp.outputs.resourceId + +@description('Name of the container app.') +output name string = containerApp.outputs.name + +@description('Fully qualified domain name of the container app.') +output fqdn string = containerApp.outputs.fqdn + +@description('Principal ID of the system-assigned managed identity.') +output systemAssignedMIPrincipalId string? = containerApp.outputs.?systemAssignedMIPrincipalId diff --git a/infra/avm/modules/compute/container-app.bicep b/infra/avm/modules/compute/container-app.bicep index 07e7b4f9..d812a985 100644 --- a/infra/avm/modules/compute/container-app.bicep +++ b/infra/avm/modules/compute/container-app.bicep @@ -1,105 +1,116 @@ // ============================================================================ -// Module: Azure Container App (AVM) +// Module: Container App +// Description: AVM wrapper for Azure Container Apps // AVM Module: avm/res/app/container-app:0.22.1 // ============================================================================ @description('Name of the container app.') param name string -@description('Azure region for deployment.') +@description('Azure region for the resource.') param location string -@description('Resource tags.') +@description('Tags to apply to the resource.') param tags object = {} -@description('Resource ID of the Container Apps Environment.') +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Resource ID of the container app environment.') param environmentResourceId string -@description('Container definitions.') +@description('Optional. Managed identity configuration.') +param managedIdentities object = {} + +@description('Optional. Container registry configuration.') +param registries array = [] + +@description('Container definitions for the container app.') param containers array -@description('Enable external ingress.') -param ingressExternal bool = true +@description('Optional. Active revisions mode.') +param activeRevisionsMode string = 'Single' -@description('Target port for ingress.') -param ingressTargetPort int = 80 +@description('Optional. Minimum replica count alias used when scaleSettings is not supplied.') +param scaleMinReplicas int = -1 -@description('Ingress transport protocol.') -@allowed(['auto', 'http', 'http2', 'tcp']) -param ingressTransport string = 'auto' +@description('Optional. Maximum replica count alias used when scaleSettings is not supplied.') +param scaleMaxReplicas int = -1 -@description('Whether to allow insecure ingress connections.') -param ingressAllowInsecure bool = false +@description('Optional. Full scale settings object.') +param scaleSettings object = {} -@description('Disable ingress entirely (for background workers).') -param disableIngress bool = false +@description('Optional. Ingress target port.') +param ingressTargetPort int = -1 -@description('Container registry configurations.') -param registries array? +@description('Whether ingress is external.') +param ingressExternal bool = false -@description('Secret definitions.') -param secrets array? +@description('Optional. Ingress transport setting.') +param ingressTransport string = '' -@description('Managed identity configuration.') -param managedIdentities object = {} +@description('Optional. Secret definitions for the container app.') +param secrets array = [] -@description('CORS policy configuration.') -param corsPolicy object = {} +@description('Optional. Workload profile name.') +param workloadProfileName string = '' -@description('Active revision mode.') -@allowed(['Single', 'Multiple']) -param activeRevisionsMode string = 'Single' +@description('Optional. Whether ingress is disabled.') +param disableIngress bool = false -@description('Scale settings (maxReplicas, minReplicas, rules, cooldownPeriod, pollingInterval).') -param scaleSettings object = { - maxReplicas: 10 - minReplicas: 0 -} +@description('Optional. Whether insecure ingress traffic is allowed.') +param ingressAllowInsecure bool = false -@description('Workload profile name.') -param workloadProfileName string? +@description('Optional. CORS policy configuration.') +param corsPolicy object = {} -@description('Enable Azure telemetry collection.') -param enableTelemetry bool = true +var resolvedScaleSettings = !empty(scaleSettings) + ? scaleSettings + : (scaleMinReplicas != -1 || scaleMaxReplicas != -1 + ? union( + scaleMinReplicas != -1 ? { minReplicas: scaleMinReplicas } : {}, + scaleMaxReplicas != -1 ? { maxReplicas: scaleMaxReplicas } : {} + ) + : null) // ============================================================================ -// Container App (AVM) +// AVM Module Deployment // ============================================================================ module containerApp 'br/public:avm/res/app/container-app:0.22.1' = { - name: take('avm.res.app.containerapp.${name}', 64) + name: take('avm.res.app.container-app.${name}', 64) params: { name: name location: location tags: tags enableTelemetry: enableTelemetry environmentResourceId: environmentResourceId + managedIdentities: empty(managedIdentities) ? null : managedIdentities + registries: !empty(registries) ? registries : null containers: containers - ingressExternal: disableIngress ? false : ingressExternal - ingressTargetPort: ingressTargetPort - ingressTransport: ingressTransport - ingressAllowInsecure: ingressAllowInsecure + activeRevisionsMode: !empty(activeRevisionsMode) ? activeRevisionsMode : null + scaleSettings: resolvedScaleSettings + ingressTargetPort: ingressTargetPort != -1 ? ingressTargetPort : null + ingressExternal: ingressExternal + ingressTransport: !empty(ingressTransport) ? ingressTransport : null + secrets: !empty(secrets) ? secrets : null + workloadProfileName: !empty(workloadProfileName) ? workloadProfileName : null disableIngress: disableIngress - registries: registries - secrets: secrets - managedIdentities: !empty(managedIdentities) ? managedIdentities : {} - corsPolicy: !empty(corsPolicy) ? corsPolicy : null - activeRevisionsMode: activeRevisionsMode - scaleSettings: scaleSettings - workloadProfileName: workloadProfileName + ingressAllowInsecure: ingressAllowInsecure + corsPolicy: empty(corsPolicy) ? null : corsPolicy } } // ============================================================================ // Outputs // ============================================================================ -@description('The name of the container app.') -output name string = containerApp.outputs.name - -@description('The resource ID of the container app.') +@description('Resource ID of the container app.') output resourceId string = containerApp.outputs.resourceId -@description('The FQDN of the container app.') +@description('Name of the container app.') +output name string = containerApp.outputs.name + +@description('Fully qualified domain name of the container app.') output fqdn string = containerApp.outputs.fqdn -@description('System-assigned identity principal ID.') -output principalId string = containerApp.outputs.?systemAssignedMIPrincipalId ?? '' +@description('Principal ID of the system-assigned managed identity.') +output systemAssignedMIPrincipalId string? = containerApp.outputs.?systemAssignedMIPrincipalId diff --git a/infra/avm/modules/compute/maintenance-configuration.bicep b/infra/avm/modules/compute/maintenance-configuration.bicep index 2683939d..c45d54e0 100644 --- a/infra/avm/modules/compute/maintenance-configuration.bicep +++ b/infra/avm/modules/compute/maintenance-configuration.bicep @@ -1,15 +1,11 @@ // ============================================================================ // Module: Maintenance Configuration // Description: AVM wrapper for Azure Maintenance Configuration -// AVM Module: avm/res/maintenance/maintenance-configuration -// WAF: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines +// AVM Module: avm/res/maintenance/maintenance-configuration:0.4.0 // ============================================================================ -@description('Solution name suffix used to derive the resource name.') -param solutionName string - @description('Name of the maintenance configuration.') -param name string = 'mc-${solutionName}' +param name string @description('Azure region for the resource.') param location string @@ -17,48 +13,24 @@ param location string @description('Tags to apply to the resource.') param tags object = {} -@description('Maintenance scope.') -param maintenanceScope string = 'InGuestPatch' +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true -@description('Visibility of the configuration.') -param visibility string = 'Custom' +@description('Optional. Extension properties for the maintenance configuration.') +param extensionProperties object = {} -@description('Extension properties.') -param extensionProperties object = { - InGuestPatchMode: 'User' -} +@description('Maintenance scope for the configuration.') +param maintenanceScope string @description('Maintenance window configuration.') -param maintenanceWindow object = { - startDateTime: '2024-06-16 00:00' - duration: '03:55' - timeZone: 'W. Europe Standard Time' - recurEvery: '1Day' -} +param maintenanceWindow object -@description('Install patches configuration.') -param installPatches object = { - rebootSetting: 'IfRequired' - windowsParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } - linuxParameters: { - classificationsToInclude: [ - 'Critical' - 'Security' - ] - } -} +@description('Visibility of the maintenance configuration.') +param visibility string = 'Custom' -@description('Enable Azure telemetry collection.') -param enableTelemetry bool = true +@description('Install patches configuration.') +param installPatches object -// ============================================================================ -// AVM Module Deployment -// ============================================================================ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.4.0' = { name: take('avm.res.maintenance.maintenance-configuration.${name}', 64) params: { @@ -74,9 +46,6 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi } } -// ============================================================================ -// Outputs -// ============================================================================ @description('Resource ID of the maintenance configuration.') output resourceId string = maintenanceConfiguration.outputs.resourceId diff --git a/infra/avm/modules/compute/virtual-machine.bicep b/infra/avm/modules/compute/virtual-machine.bicep index 8b9c2a7e..608d0a4d 100644 --- a/infra/avm/modules/compute/virtual-machine.bicep +++ b/infra/avm/modules/compute/virtual-machine.bicep @@ -1,15 +1,11 @@ // ============================================================================ -// Module: Virtual Machine (Jumpbox) -// Description: AVM wrapper for Azure Virtual Machine with Entra ID authentication -// AVM Module: avm/res/compute/virtual-machine -// Ref: https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication +// Module: Virtual Machine +// Description: AVM wrapper for Azure Virtual Machine +// AVM Module: avm/res/compute/virtual-machine:0.22.0 // ============================================================================ -@description('Solution name suffix used to derive the resource name.') -param solutionName string - @description('Name of the virtual machine.') -param name string = 'vm-${solutionName}' +param name string @description('Azure region for the resource.') param location string @@ -17,70 +13,67 @@ param location string @description('Tags to apply to the resource.') param tags object = {} -@description('VM size.') -param vmSize string = 'Standard_D2s_v5' +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Computer name of the virtual machine.') +param computerName string = '' -@secure() -@description('Local admin username. Required by Azure at provisioning time but not used for login when Entra ID is enabled.') +@description('Operating system type.') +param osType string + +@description('Virtual machine size.') +param vmSize string + +@description('Administrator username for the virtual machine.') param adminUsername string +@description('Administrator password for the virtual machine.') @secure() -@description('Local admin password. Required by Azure at provisioning time but not used for login when Entra ID is enabled.') param adminPassword string -@description('Resource ID of the subnet for the VM NIC.') -param subnetResourceId string +@description('Optional. Managed identity configuration.') +param managedIdentities object? -@description('OS type for the VM.') -param osType string = 'Windows' +@description('Optional. Patch mode for the virtual machine.') +param patchMode string = '' -@description('Availability zone for the VM.') -param availabilityZone int = 1 +@description('Optional. Whether platform safety checks should be bypassed for user schedules.') +param bypassPlatformSafetyChecksOnUserSchedule bool = false -@description('Image reference for the VM.') -param imageReference object = { - publisher: 'microsoft-dsvm' - offer: 'dsvm-win-2022' - sku: 'winserver-2022' - version: 'latest' -} +@description('Optional. Maintenance configuration resource ID.') +param maintenanceConfigurationResourceId string = '' -@description('OS disk size in GB.') -param osDiskSizeGB int = 128 +@description('Optional. Whether automatic updates are enabled.') +param enableAutomaticUpdates bool = false -@description('Resource ID of the maintenance configuration.') -param maintenanceConfigurationResourceId string? +@description('Whether to enable encryption at host.') +param encryptionAtHost bool = false -@description('Resource ID of the proximity placement group.') -param proximityPlacementGroupResourceId string? +@description('Optional. Availability zone for the virtual machine.') +param availabilityZone int = -1 -@description('Monitoring agent extension configuration (data collection rule associations).') -param extensionMonitoringAgentConfig object? +@description('Image reference used to create the virtual machine.') +param imageReference object -@description('Diagnostic settings for the resource.') -param diagnosticSettings array? +@description('OS disk configuration for the virtual machine.') +param osDisk object -@description('Enable Azure telemetry collection.') -param enableTelemetry bool = true +@description('Network interface configurations for the virtual machine.') +param nicConfigurations array -@description('Deploying user principal ID. Used for default role assignment to grant the deploying user login access to the VM. This is required because with Entra ID authentication enabled, local accounts cannot be used to access the VM, including the local admin account created at provisioning.') -param deployingUserPrincipalId string +@description('Optional. Azure AD join extension configuration.') +param extensionAadJoinConfig object? -@description('Deploying user principal type. Used for default role assignment to grant the deploying user login access to the VM. This is required because with Entra ID authentication enabled, local accounts cannot be used to access the VM, including the local admin account created at provisioning.') -param deployingUserPrincipalType string = 'User' +@description('Optional. Anti-malware extension configuration.') +param extensionAntiMalwareConfig object? -@description('Role assignments to apply to the virtual machine.') -param roleAssignments array = [ - { - roleDefinitionIdOrName: '1c0163c0-47e6-4577-8991-ea5c82e286e4' // Virtual Machine Administrator Login - principalId: deployingUserPrincipalId - principalType: deployingUserPrincipalType - } -] +@description('Optional. Monitoring agent extension configuration.') +param extensionMonitoringAgentConfig object? + +@description('Optional. Network watcher extension configuration.') +param extensionNetworkWatcherAgentConfig object? -// ============================================================================ -// AVM Module Deployment -// ============================================================================ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.22.0' = { name: take('avm.res.compute.virtual-machine.${name}', 64) params: { @@ -88,68 +81,28 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.22.0' = { location: location tags: tags enableTelemetry: enableTelemetry - computerName: take(name, 15) + computerName: !empty(computerName) ? computerName : null osType: osType vmSize: vmSize adminUsername: adminUsername adminPassword: adminPassword - managedIdentities: { systemAssigned: true } - patchMode: 'AutomaticByPlatform' - bypassPlatformSafetyChecksOnUserSchedule: true - maintenanceConfigurationResourceId: maintenanceConfigurationResourceId - enableAutomaticUpdates: true - encryptionAtHost: true + managedIdentities: managedIdentities + patchMode: !empty(patchMode) ? patchMode : null + bypassPlatformSafetyChecksOnUserSchedule: bypassPlatformSafetyChecksOnUserSchedule + maintenanceConfigurationResourceId: !empty(maintenanceConfigurationResourceId) ? maintenanceConfigurationResourceId : null + enableAutomaticUpdates: enableAutomaticUpdates + encryptionAtHost: encryptionAtHost availabilityZone: availabilityZone - proximityPlacementGroupResourceId: proximityPlacementGroupResourceId imageReference: imageReference - osDisk: { - name: 'osdisk-${name}' - caching: 'ReadWrite' - createOption: 'FromImage' - deleteOption: 'Delete' - diskSizeGB: osDiskSizeGB - managedDisk: { storageAccountType: 'Premium_LRS' } - } - nicConfigurations: [ - { - name: 'nic-${name}' - tags: tags - deleteOption: 'Delete' - diagnosticSettings: diagnosticSettings - ipConfigurations: [ - { - name: '${name}-nic01-ipconfig01' - subnetResourceId: subnetResourceId - diagnosticSettings: diagnosticSettings - } - ] - } - ] - roleAssignments: roleAssignments - extensionAadJoinConfig: { - enabled: true - tags: tags - typeHandlerVersion: '2.0' - settings: { mdmId: '' } - } - extensionAntiMalwareConfig: { - enabled: true - settings: { - AntimalwareEnabled: 'true' - Exclusions: {} - RealtimeProtectionEnabled: 'true' - ScheduledScanSettings: { day: '7', isEnabled: 'true', scanType: 'Quick', time: '120' } - } - tags: tags - } + osDisk: osDisk + nicConfigurations: nicConfigurations + extensionAadJoinConfig: extensionAadJoinConfig + extensionAntiMalwareConfig: extensionAntiMalwareConfig extensionMonitoringAgentConfig: extensionMonitoringAgentConfig - extensionNetworkWatcherAgentConfig: { enabled: true, tags: tags } + extensionNetworkWatcherAgentConfig: extensionNetworkWatcherAgentConfig } } -// ============================================================================ -// Outputs -// ============================================================================ @description('Resource ID of the virtual machine.') output resourceId string = virtualMachine.outputs.resourceId diff --git a/infra/avm/modules/data/app-configuration.bicep b/infra/avm/modules/data/app-configuration.bicep index ee3fb318..13048397 100644 --- a/infra/avm/modules/data/app-configuration.bicep +++ b/infra/avm/modules/data/app-configuration.bicep @@ -1,98 +1,76 @@ // ============================================================================ -// Module: Azure App Configuration (AVM) +// Module: App Configuration +// Description: AVM wrapper for Azure App Configuration +// AVM Module: avm/res/app-configuration/configuration-store:0.9.2 // ============================================================================ -@description('Solution name used for naming convention.') -param solutionName string - @description('Name of the App Configuration store.') -param name string = 'appcs-${solutionName}' +param name string -@description('Azure region for deployment.') +@description('Azure region for the resource.') param location string -@description('Resource tags.') +@description('Whether purge protection is enabled.') +param enablePurgeProtection bool = false + +@description('Tags to apply to the resource.') param tags object = {} -@description('Enable Azure telemetry collection.') +@description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -@description('SKU for the configuration store.') -@allowed(['Free', 'Standard']) -param sku string = 'Standard' +@description('Managed identity configuration.') +param managedIdentities object? -@description('Disable local (key-based) authentication.') -param disableLocalAuth bool = true +@description('SKU for the App Configuration store.') +param sku string = 'Standard' -@description('Enable purge protection.') -param enablePurgeProtection bool = false +@description('Optional. Diagnostic settings to apply to the App Configuration store.') +param diagnosticSettings array? -@description('Soft delete retention in days.') -param softDeleteRetentionInDays int = 7 +@description('Whether local authentication is disabled.') +param disableLocalAuth bool = false -@description('Managed identity configuration.') -param managedIdentities object = {} +@description('Optional. Replica locations for the App Configuration store.') +param replicaLocations array = [] -@description('Role assignments.') +@description('Role assignments for the App Configuration store.') param roleAssignments array = [] -@description('Key-value pairs to store in the configuration.') +@description('Key-values to create in the App Configuration store.') param keyValues array = [] -@description('Enable private networking.') -param enablePrivateNetworking bool = false - -@description('Subnet resource ID for private endpoint.') -param privateEndpointSubnetId string = '' - -@description('Private DNS zone resource IDs.') -param privateDnsZoneResourceIds array = [] +@description('Public network access setting.') +param publicNetworkAccess string = 'Enabled' -// ============================================================================ -// App Configuration (AVM) -// ============================================================================ +@description('Optional. Private endpoint configuration.') +param privateEndpoints array = [] -var dnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { - name: 'config${i}' - privateDnsZoneResourceId: zoneId -}] - -var privateEndpointConfig = enablePrivateNetworking && !empty(privateEndpointSubnetId) ? [ - { - subnetResourceId: privateEndpointSubnetId - privateDnsZoneGroup: !empty(privateDnsZoneResourceIds) ? { - privateDnsZoneGroupConfigs: dnsZoneConfigs - } : null - } -] : [] - -module configStore 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { - name: take('avm.res.appconfiguration.${name}', 64) +module appConfiguration 'br/public:avm/res/app-configuration/configuration-store:0.9.2' = { + name: take('avm.res.app-configuration.configuration-store.${name}', 64) params: { name: name location: location + enablePurgeProtection: enablePurgeProtection tags: tags enableTelemetry: enableTelemetry + managedIdentities: managedIdentities sku: sku + diagnosticSettings: diagnosticSettings disableLocalAuth: disableLocalAuth - enablePurgeProtection: enablePurgeProtection - softDeleteRetentionInDays: softDeleteRetentionInDays - managedIdentities: !empty(managedIdentities) ? managedIdentities : {} - roleAssignments: !empty(roleAssignments) ? roleAssignments : [] - keyValues: !empty(keyValues) ? keyValues : [] - privateEndpoints: privateEndpointConfig + replicaLocations: replicaLocations + roleAssignments: roleAssignments + keyValues: keyValues + publicNetworkAccess: publicNetworkAccess + privateEndpoints: privateEndpoints } } -// ============================================================================ -// Outputs -// ============================================================================ +@description('Resource ID of the App Configuration store.') +output resourceId string = appConfiguration.outputs.resourceId -@description('The name of the configuration store.') -output name string = configStore.outputs.name - -@description('The endpoint of the configuration store.') -output endpoint string = configStore.outputs.endpoint +@description('Name of the App Configuration store.') +output name string = appConfiguration.outputs.name -@description('The resource ID of the configuration store.') -output resourceId string = configStore.outputs.resourceId +@description('Endpoint of the App Configuration store.') +output endpoint string = appConfiguration.outputs.endpoint diff --git a/infra/avm/modules/data/storage-account.bicep b/infra/avm/modules/data/storage-account.bicep index 1ff0e497..b6647f56 100644 --- a/infra/avm/modules/data/storage-account.bicep +++ b/infra/avm/modules/data/storage-account.bicep @@ -1,135 +1,76 @@ // ============================================================================ // Module: Storage Account -// Description: AVM wrapper for Azure Storage Account with WAF alignment +// Description: AVM wrapper for Azure Storage Account // AVM Module: avm/res/storage/storage-account:0.32.0 -// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/storage-accounts // ============================================================================ -@description('Solution name suffix used to derive the resource name.') -param solutionName string - @description('Name of the storage account.') -param name string = take('st${toLower(replace(solutionName, '-', ''))}', 24) +param name string @description('Azure region for the resource.') param location string -@description('Tags to apply to the resource.') -param tags object = {} +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true -@description('Storage account SKU.') -param skuName string = 'Standard_LRS' +@description('Managed identity configuration.') +param managedIdentities object -@description('Storage account kind.') -param kind string = 'StorageV2' +@description('Minimum TLS version.') +param minimumTlsVersion string = 'TLS1_2' -@description('Access tier.') -@allowed(['Hot', 'Cool']) -param accessTier string = 'Hot' +@description('Role assignments for the storage account.') +param roleAssignments array -@description('Allow blob public access.') -param allowBlobPublicAccess bool = false +@description('Network ACL configuration.') +param networkAcls object -@description('Allow shared key access.') -param allowSharedKeyAccess bool = true +@description('Whether infrastructure encryption is required.') +param requireInfrastructureEncryption bool = false -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true +@description('Whether HTTPS traffic only is enforced.') +param supportsHttpsTrafficOnly bool = true -@description('Blob containers to create.') -param containers array = [ - { - name: 'default' - publicAccess: 'None' - } -] +@description('Access tier for the storage account.') +param accessTier string = 'Hot' + +@description('Tags to apply to the resource.') +param tags object = {} -// --- WAF: Monitoring --- -@description('Diagnostic settings for monitoring.') -param diagnosticSettings array = [] +@description('Whether blob public access is allowed.') +param allowBlobPublicAccess bool = false -// --- WAF: Private Networking --- @description('Public network access setting.') param publicNetworkAccess string = 'Enabled' -@description('Network ACLs for the storage account.') -param networkAcls object = { - defaultAction: 'Allow' - bypass: 'AzureServices' -} +@description('Optional. Private endpoint configuration.') +param privateEndpoints array = [] -@description('Whether to enable private networking.') -param enablePrivateNetworking bool = false - -@description('Subnet resource ID for the private endpoint.') -param privateEndpointSubnetId string = '' - -@description('Private DNS zone resource IDs for Storage (blob).') -param privateDnsZoneResourceIds array = [] - -var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: { - name: 'dns-zone-${i}' - privateDnsZoneResourceId: zoneId -}] - -// --- Role Assignments --- -@description('Optional. Array of role assignments to create on the Storage Account.') -param roleAssignments array = [] - -// ============================================================================ -// AVM Module Deployment -// ============================================================================ -module storage 'br/public:avm/res/storage/storage-account:0.32.0' = { +module storageAccount 'br/public:avm/res/storage/storage-account:0.32.0' = { name: take('avm.res.storage.storage-account.${name}', 64) params: { name: name location: location - tags: tags enableTelemetry: enableTelemetry - skuName: skuName - kind: kind + managedIdentities: managedIdentities + minimumTlsVersion: minimumTlsVersion + roleAssignments: roleAssignments + networkAcls: networkAcls + requireInfrastructureEncryption: requireInfrastructureEncryption + supportsHttpsTrafficOnly: supportsHttpsTrafficOnly accessTier: accessTier + tags: tags allowBlobPublicAccess: allowBlobPublicAccess - allowSharedKeyAccess: allowSharedKeyAccess - minimumTlsVersion: 'TLS1_2' - supportsHttpsTrafficOnly: true - requireInfrastructureEncryption: true publicNetworkAccess: publicNetworkAccess - networkAcls: networkAcls - blobServices: { - containers: [for container in containers: { - name: container.name - publicAccess: container.publicAccess - }] - diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] - } - diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : [] - privateEndpoints: enablePrivateNetworking ? [ - { - name: 'pep-${name}' - customNetworkInterfaceName: 'nic-${name}' - subnetResourceId: privateEndpointSubnetId - service: 'blob' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: privateDnsZoneConfigs - } - } - ] : [] - roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + privateEndpoints: privateEndpoints } } -// ============================================================================ -// Outputs -// ============================================================================ -@description('Resource ID of the Storage Account.') -output resourceId string = storage.outputs.resourceId - -@description('Name of the Storage Account.') -output name string = storage.outputs.name +@description('Resource ID of the storage account.') +output resourceId string = storageAccount.outputs.resourceId -@description('Primary blob endpoint.') -output blobEndpoint string = storage.outputs.primaryBlobEndpoint +@description('Name of the storage account.') +output name string = storageAccount.outputs.name -@description('Service endpoints.') -output serviceEndpoints object = storage.outputs.serviceEndpoints +@description('Service endpoints exposed by the storage account.') +output serviceEndpoints object = storageAccount.outputs.serviceEndpoints diff --git a/infra/avm/modules/identity/role-assignments.bicep b/infra/avm/modules/identity/role-assignments.bicep index 399e4ae1..9f68de55 100644 --- a/infra/avm/modules/identity/role-assignments.bicep +++ b/infra/avm/modules/identity/role-assignments.bicep @@ -19,12 +19,9 @@ param existingFoundryProjectResourceId string = '' // --- Identity Principal IDs --- -@description('Principal ID of the AI project identity.') +@description('Principal ID of the AI project identity (works for both new and existing projects).') param aiProjectPrincipalId string = '' -@description('Principal ID of the existing AI project identity (for cross-service roles).') -param existingAiProjectPrincipalId string = '' - @description('Principal ID of the AI Search identity.') param aiSearchPrincipalId string = '' @@ -99,7 +96,7 @@ resource cosmosContributorRoleDefinition 'Microsoft.DocumentDB/databaseAccounts/ // AI Search → Cognitive Services OpenAI User on AI Foundry (new project, same RG) resource assignOpenAIRoleToAISearch 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiSearchPrincipalId) && !empty(aiFoundryResourceId)) { - name: guid(aiFoundryAccount.id, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + name: guid(solutionName, aiFoundryAccount.id, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) scope: aiFoundryAccount properties: { principalId: aiSearchPrincipalId @@ -115,14 +112,14 @@ module assignOpenAIToSearchExisting './cross-scope-role-assignment.bicep' = if ( params: { principalId: aiSearchPrincipalId roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) - roleAssignmentName: guid(existingAIFoundryName, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) + roleAssignmentName: guid(solutionName, existingAIFoundryName, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) aiFoundryName: existingAIFoundryName } } // Backend App Service → Foundry User on AI Foundry (new project, same RG) resource backendAppAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiFoundryResourceId) && !empty(backendAppServicePrincipalId)) { - name: guid(aiFoundryAccount.id, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + name: guid(solutionName, aiFoundryAccount.id, backendAppServicePrincipalId, roleDefinitions.azureAiUser) scope: aiFoundryAccount properties: { principalId: backendAppServicePrincipalId @@ -138,7 +135,7 @@ module backendAppAiUserExisting './cross-scope-role-assignment.bicep' = if (useE params: { principalId: backendAppServicePrincipalId roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) - roleAssignmentName: guid(existingAIFoundryName, backendAppServicePrincipalId, roleDefinitions.azureAiUser) + roleAssignmentName: guid(solutionName, existingAIFoundryName, backendAppServicePrincipalId, roleDefinitions.azureAiUser) aiFoundryName: existingAIFoundryName } } @@ -148,9 +145,9 @@ module backendAppAiUserExisting './cross-scope-role-assignment.bicep' = if (useE // AI Project and Backend identities → AI Search // ============================================================================ -// AI Project → Search Index Data Reader on AI Search (new project) +// AI Project → Search Index Data Reader on AI Search resource projectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchIndexDataReader) + name: guid(solutionName, aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchIndexDataReader) scope: aiSearchService properties: { principalId: aiProjectPrincipalId @@ -159,9 +156,9 @@ resource projectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01 } } -// AI Project → Search Service Contributor on AI Search (new project) +// AI Project → Search Service Contributor on AI Search resource projectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchServiceContributor) + name: guid(solutionName, aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchServiceContributor) scope: aiSearchService properties: { principalId: aiProjectPrincipalId @@ -170,31 +167,9 @@ resource projectSearchContributor 'Microsoft.Authorization/roleAssignments@2022- } } -// Existing AI Project → Search Index Data Reader on AI Search -resource existingProjectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchIndexDataReader) - scope: aiSearchService - properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) - principalType: 'ServicePrincipal' - } -} - -// Existing AI Project → Search Service Contributor on AI Search -resource existingProjectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchServiceContributor) - scope: aiSearchService - properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) - principalType: 'ServicePrincipal' - } -} - // Backend App Service → Search Index Data Reader on AI Search resource backendAppSearchReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(backendAppServicePrincipalId)) { - name: guid(aiSearchService.id, backendAppServicePrincipalId, roleDefinitions.searchIndexDataReader) + name: guid(solutionName, aiSearchService.id, backendAppServicePrincipalId, roleDefinitions.searchIndexDataReader) scope: aiSearchService properties: { principalId: backendAppServicePrincipalId @@ -208,9 +183,9 @@ resource backendAppSearchReaderAssignment 'Microsoft.Authorization/roleAssignmen // AI Project, AI Search, and Existing Project identities → Storage // ============================================================================ -// AI Project → Storage Blob Data Contributor (new project) +// AI Project → Storage Blob Data Contributor resource projectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) + name: guid(solutionName, storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) scope: storageAccount properties: { principalId: aiProjectPrincipalId @@ -219,9 +194,9 @@ resource projectStorageContributor 'Microsoft.Authorization/roleAssignments@2022 } } -// AI Project → Storage Blob Data Reader (new project) +// AI Project → Storage Blob Data Reader resource projectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataReader) + name: guid(solutionName, storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataReader) scope: storageAccount properties: { principalId: aiProjectPrincipalId @@ -230,31 +205,9 @@ resource projectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-0 } } -// Existing AI Project → Storage Blob Data Contributor -resource existingProjectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) - scope: storageAccount - properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) - principalType: 'ServicePrincipal' - } -} - -// Existing AI Project → Storage Blob Data Reader -resource existingProjectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataReader) - scope: storageAccount - properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) - principalType: 'ServicePrincipal' - } -} - // AI Search → Storage Blob Data Reader resource searchStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiSearchPrincipalId)) { - name: guid(storageAccount.id, aiSearchPrincipalId, roleDefinitions.storageBlobDataReader) + name: guid(solutionName, storageAccount.id, aiSearchPrincipalId, roleDefinitions.storageBlobDataReader) scope: storageAccount properties: { principalId: aiSearchPrincipalId @@ -270,11 +223,10 @@ resource searchStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01 resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) { parent: cosmosAccount - name: guid(cosmosContributorRoleDefinition.id, cosmosAccount.id, backendAppServicePrincipalId) + name: guid(solutionName, cosmosContributorRoleDefinition.id, cosmosAccount.id, backendAppServicePrincipalId) properties: { principalId: backendAppServicePrincipalId roleDefinitionId: cosmosContributorRoleDefinition.id scope: cosmosAccount.id } } - diff --git a/infra/avm/modules/monitoring/app-insights.bicep b/infra/avm/modules/monitoring/app-insights.bicep index b726ae81..ee364445 100644 --- a/infra/avm/modules/monitoring/app-insights.bicep +++ b/infra/avm/modules/monitoring/app-insights.bicep @@ -1,76 +1,60 @@ // ============================================================================ // Module: Application Insights -// Description: AVM wrapper for Application Insights with WAF alignment +// Description: AVM wrapper for Application Insights component // AVM Module: avm/res/insights/component:0.7.1 -// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/application-insights // ============================================================================ -@description('Solution name suffix used to derive the resource name.') -param solutionName string - -@description('Optional. Override name for the Application Insights instance. Defaults to appi-{solutionName}.') -param name string = 'appi-${solutionName}' +@description('Name of the Application Insights component.') +param name string @description('Azure region for the resource.') param location string -@description('Tags to apply to the resource.') -param tags object = {} - -@description('Resource ID of the Log Analytics workspace to link to.') -param workspaceResourceId string - -@description('Application type.') -param applicationType string = 'web' +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true -@description('Retention period in days. WAF recommends 365.') +@description('Retention period in days.') param retentionInDays int = 365 -@description('Disable IP masking for security. WAF recommends false.') +@description('Application type for the component.') +param kind string = 'web' + +@description('Whether to disable IP masking.') param disableIpMasking bool = false -@description('Flow type for Application Insights.') +@description('Flow type for the component.') param flowType string = 'Bluefield' -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true +@description('Resource ID of the Log Analytics workspace connected to the component.') +param workspaceResourceId string = '' -@description('Kind of Application Insights resource.') -param kind string = 'web' +@description('Optional. Diagnostic settings to apply to the component.') +param diagnosticSettings array? + +@description('Tags to apply to the resource.') +param tags object = {} -// ============================================================================ -// AVM Module Deployment -// ============================================================================ module appInsights 'br/public:avm/res/insights/component:0.7.1' = { name: take('avm.res.insights.component.${name}', 64) params: { name: name location: location - tags: tags - workspaceResourceId: workspaceResourceId - kind: kind - applicationType: applicationType enableTelemetry: enableTelemetry retentionInDays: retentionInDays + kind: kind disableIpMasking: disableIpMasking flowType: flowType + workspaceResourceId: workspaceResourceId + diagnosticSettings: diagnosticSettings + tags: tags } } -// ============================================================================ -// Outputs -// ============================================================================ -@description('Resource ID of the Application Insights instance.') +@description('Resource ID of the Application Insights component.') output resourceId string = appInsights.outputs.resourceId -@description('Name of the Application Insights instance.') +@description('Name of the Application Insights component.') output name string = appInsights.outputs.name -@description('Instrumentation key for the Application Insights instance.') -output instrumentationKey string = appInsights.outputs.instrumentationKey - -@description('Connection string for the Application Insights instance.') +@description('Connection string of the Application Insights component.') output connectionString string = appInsights.outputs.connectionString - -@description('Application ID of the Application Insights instance.') -output applicationId string = appInsights.outputs.applicationId diff --git a/infra/avm/modules/monitoring/data-collection-rule.bicep b/infra/avm/modules/monitoring/data-collection-rule.bicep index c1fd7606..11f20ade 100644 --- a/infra/avm/modules/monitoring/data-collection-rule.bicep +++ b/infra/avm/modules/monitoring/data-collection-rule.bicep @@ -1,15 +1,11 @@ // ============================================================================ // Module: Data Collection Rule -// Description: AVM wrapper for Azure Monitor Data Collection Rule -// AVM Module: avm/res/insights/data-collection-rule -// WAF: Monitoring for VM observability +// Description: AVM wrapper for Azure Monitor data collection rules +// AVM Module: avm/res/insights/data-collection-rule:0.11.0 // ============================================================================ -@description('Solution name suffix used to derive the resource name.') -param solutionName string - -@description('Optional. Override name for the data collection rule. Defaults to dcr-{solutionName}.') -param name string = 'dcr-${solutionName}' +@description('Name of the data collection rule.') +param name string @description('Azure region for the resource.') param location string @@ -17,131 +13,23 @@ param location string @description('Tags to apply to the resource.') param tags object = {} -@description('Resource ID of the Log Analytics workspace destination.') -param logAnalyticsWorkspaceResourceId string - -@description('Name of the Log Analytics workspace (used for destination naming).') -param logAnalyticsWorkspaceName string = '' - @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -var dcrLogAnalyticsDestinationName = !empty(logAnalyticsWorkspaceName) ? 'la-${logAnalyticsWorkspaceName}-destination' : 'la-${name}-destination' +@description('Properties block for the data collection rule.') +param dataCollectionRuleProperties object -// ============================================================================ -// AVM Module Deployment -// ============================================================================ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:0.11.0' = { name: take('avm.res.insights.data-collection-rule.${name}', 64) params: { name: name + location: location tags: tags enableTelemetry: enableTelemetry - location: location - dataCollectionRuleProperties: { - kind: 'Windows' - dataSources: { - performanceCounters: [ - { - streams: ['Microsoft-Perf'] - samplingFrequencyInSeconds: 60 - counterSpecifiers: [ - '\\Processor Information(_Total)\\% Processor Time' - '\\Processor Information(_Total)\\% Privileged Time' - '\\Processor Information(_Total)\\% User Time' - '\\Processor Information(_Total)\\Processor Frequency' - '\\System\\Processes' - '\\Process(_Total)\\Thread Count' - '\\Process(_Total)\\Handle Count' - '\\System\\System Up Time' - '\\System\\Context Switches/sec' - '\\System\\Processor Queue Length' - '\\Memory\\% Committed Bytes In Use' - '\\Memory\\Available Bytes' - '\\Memory\\Committed Bytes' - '\\Memory\\Cache Bytes' - '\\Memory\\Pool Paged Bytes' - '\\Memory\\Pool Nonpaged Bytes' - '\\Memory\\Pages/sec' - '\\Memory\\Page Faults/sec' - '\\Process(_Total)\\Working Set' - '\\Process(_Total)\\Working Set - Private' - '\\LogicalDisk(_Total)\\% Disk Time' - '\\LogicalDisk(_Total)\\% Disk Read Time' - '\\LogicalDisk(_Total)\\% Disk Write Time' - '\\LogicalDisk(_Total)\\% Idle Time' - '\\LogicalDisk(_Total)\\Disk Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' - '\\LogicalDisk(_Total)\\Disk Transfers/sec' - '\\LogicalDisk(_Total)\\Disk Reads/sec' - '\\LogicalDisk(_Total)\\Disk Writes/sec' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' - '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' - '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' - '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' - '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' - '\\LogicalDisk(_Total)\\% Free Space' - '\\LogicalDisk(_Total)\\Free Megabytes' - '\\Network Interface(*)\\Bytes Total/sec' - '\\Network Interface(*)\\Bytes Sent/sec' - '\\Network Interface(*)\\Bytes Received/sec' - '\\Network Interface(*)\\Packets/sec' - '\\Network Interface(*)\\Packets Sent/sec' - '\\Network Interface(*)\\Packets Received/sec' - '\\Network Interface(*)\\Packets Outbound Errors' - '\\Network Interface(*)\\Packets Received Errors' - ] - name: 'perfCounterDataSource60' - } - ] - windowsEventLogs: [ - { - name: 'SecurityAuditEvents' - streams: ['Microsoft-WindowsEvent'] - xPathQueries: [ - 'Security!*[System[(EventID=4624 or EventID=4625)]]' - ] - } - { - name: 'AuditSuccessFailure' - streams: ['Microsoft-Event'] - xPathQueries: [ - 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' - ] - } - ] - } - destinations: { - logAnalytics: [ - { - workspaceResourceId: logAnalyticsWorkspaceResourceId - name: dcrLogAnalyticsDestinationName - } - ] - } - dataFlows: [ - { - streams: ['Microsoft-Perf'] - destinations: [dcrLogAnalyticsDestinationName] - transformKql: 'source' - outputStream: 'Microsoft-Perf' - } - { - streams: ['Microsoft-Event'] - destinations: [dcrLogAnalyticsDestinationName] - transformKql: 'source' - outputStream: 'Microsoft-Event' - } - ] - } + dataCollectionRuleProperties: dataCollectionRuleProperties } } -// ============================================================================ -// Outputs -// ============================================================================ @description('Resource ID of the data collection rule.') output resourceId string = dataCollectionRule.outputs.resourceId diff --git a/infra/avm/modules/monitoring/workbook.bicep b/infra/avm/modules/monitoring/workbook.bicep new file mode 100644 index 00000000..1855f780 --- /dev/null +++ b/infra/avm/modules/monitoring/workbook.bicep @@ -0,0 +1,56 @@ +// ============================================================================ +// Module: Azure Workbook +// Description: Deploys an Azure Monitor Workbook +// Resource: Microsoft.Insights/workbooks@2023-06-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.insights/workbooks +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Unique ID (GUID) for the workbook resource.') +param name string = guid(resourceGroup().id, solutionName, 'workbook') + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Display name for the workbook.') +param displayName string = 'workbook-${solutionName}' + +@description('Serialized JSON content of the workbook definition.') +param serializedData string + +@description('Resource ID of the source (e.g., Log Analytics workspace or App Insights). Defaults to Azure Monitor.') +param sourceId string = 'azure monitor' + +@description('Gallery category for the workbook. E.g., workbook, tsg.') +param category string = 'workbook' + +// ============================================================================ +// Resource +// ============================================================================ +resource workbook 'Microsoft.Insights/workbooks@2023-06-01' = { + name: name + location: location + tags: tags + kind: 'shared' + properties: { + displayName: displayName + serializedData: serializedData + version: '1.0' + sourceId: sourceId + category: category + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the workbook.') +output name string = workbook.name + +@description('Resource ID of the workbook.') +output resourceId string = workbook.id diff --git a/infra/avm/modules/networking/bastion-host.bicep b/infra/avm/modules/networking/bastion-host.bicep index bf524087..6635a1ce 100644 --- a/infra/avm/modules/networking/bastion-host.bicep +++ b/infra/avm/modules/networking/bastion-host.bicep @@ -1,85 +1,49 @@ // ============================================================================ // Module: Bastion Host // Description: AVM wrapper for Azure Bastion Host -// AVM Module: avm/res/network/bastion-host +// AVM Module: avm/res/network/bastion-host:0.8.2 // ============================================================================ -@description('Solution name suffix used to derive the resource name.') -param solutionName string - -var name = 'bas-${solutionName}' +@description('Name of the Bastion host.') +param name string @description('Azure region for the resource.') param location string -@description('Tags to apply to the resource.') -param tags object = {} - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true +@description('SKU name for the Bastion host.') +param skuName string = 'Standard' -@description('Resource ID of the virtual network.') +@description('Resource ID of the virtual network hosting the AzureBastionSubnet.') param virtualNetworkResourceId string -@description('Optional. Diagnostic settings for the resource.') +@description('Optional. Diagnostic settings to apply to the Bastion host.') param diagnosticSettings array? -@description('SKU name for the Bastion Host.') -param skuName string = 'Standard' - -@description('Number of scale units.') -param scaleUnits int = 4 - -@description('Disable copy/paste functionality.') -param disableCopyPaste bool = true - -@description('Enable file copy functionality.') -param enableFileCopy bool = false - -@description('Enable IP Connect functionality.') -param enableIpConnect bool = false - -@description('Enable shareable link functionality.') -param enableShareableLink bool = false +@description('Tags to apply to the resource.') +param tags object = {} -@description('Availability zones for the Bastion Host public IP. Pass empty array to disable zone redundancy.') -param availabilityZones array = [] +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true -@description('Optional. Diagnostic settings for the public IP address.') -param publicIPDiagnosticSettings array? +@description('Public IP configuration object for the Bastion host.') +param publicIPAddressObject object -// ============================================================================ -// AVM Module Deployment -// ============================================================================ module bastionHost 'br/public:avm/res/network/bastion-host:0.8.2' = { name: take('avm.res.network.bastion-host.${name}', 64) params: { name: name location: location - tags: tags - enableTelemetry: enableTelemetry skuName: skuName virtualNetworkResourceId: virtualNetworkResourceId - availabilityZones: availabilityZones - publicIPAddressObject: { - name: 'pip-${name}' - diagnosticSettings: publicIPDiagnosticSettings - tags: tags - } - disableCopyPaste: disableCopyPaste - enableFileCopy: enableFileCopy - enableIpConnect: enableIpConnect - enableShareableLink: enableShareableLink - scaleUnits: scaleUnits diagnosticSettings: diagnosticSettings + tags: tags + enableTelemetry: enableTelemetry + publicIPAddressObject: publicIPAddressObject } } -// ============================================================================ -// Outputs -// ============================================================================ -@description('Resource ID of the Bastion Host.') +@description('Resource ID of the Bastion host.') output resourceId string = bastionHost.outputs.resourceId -@description('Name of the Bastion Host.') +@description('Name of the Bastion host.') output name string = bastionHost.outputs.name diff --git a/infra/avm/modules/networking/private-dns-zone.bicep b/infra/avm/modules/networking/private-dns-zone.bicep index 24bd2892..b88f6990 100644 --- a/infra/avm/modules/networking/private-dns-zone.bicep +++ b/infra/avm/modules/networking/private-dns-zone.bicep @@ -1,11 +1,10 @@ // ============================================================================ // Module: Private DNS Zone // Description: AVM wrapper for Azure Private DNS Zone -// AVM Module: avm/res/network/private-dns-zone -// Usage: Call once per DNS zone from main.bicep +// AVM Module: avm/res/network/private-dns-zone:0.8.1 // ============================================================================ -@description('Name of the private DNS zone (e.g., privatelink.cognitiveservices.azure.com).') +@description('Name of the private DNS zone.') param name string @description('Tags to apply to the resource.') @@ -14,12 +13,9 @@ param tags object = {} @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -@description('Virtual network links to associate with the DNS zone.') +@description('Optional. Virtual network link configurations for the private DNS zone.') param virtualNetworkLinks array = [] -// ============================================================================ -// AVM Module Deployment -// ============================================================================ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:0.8.1' = { name: take('avm.res.network.private-dns-zone.${name}', 64) params: { @@ -30,9 +26,6 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:0.8.1' = { } } -// ============================================================================ -// Outputs -// ============================================================================ @description('Resource ID of the private DNS zone.') output resourceId string = privateDnsZone.outputs.resourceId diff --git a/infra/avm/modules/networking/private-endpoint.bicep b/infra/avm/modules/networking/private-endpoint.bicep index 04bfff07..b1cab20e 100644 --- a/infra/avm/modules/networking/private-endpoint.bicep +++ b/infra/avm/modules/networking/private-endpoint.bicep @@ -1,8 +1,7 @@ // ============================================================================ // Module: Private Endpoint // Description: AVM wrapper for Azure Private Endpoint -// AVM Module: avm/res/network/private-endpoint -// Usage: Call once per private endpoint from main.bicep +// AVM Module: avm/res/network/private-endpoint:0.12.0 // ============================================================================ @description('Name of the private endpoint.') @@ -14,37 +13,31 @@ param location string @description('Tags to apply to the resource.') param tags object = {} -@description('Optional. Custom NIC name for the private endpoint.') +@description('Optional. Name of the custom network interface.') param customNetworkInterfaceName string = '' -@description('Resource ID of the subnet for the private endpoint.') -param subnetResourceId string - -@description('Private link service connections configuration.') +@description('Private link service connections.') param privateLinkServiceConnections array @description('Optional. Private DNS zone group configuration.') param privateDnsZoneGroup object? -// ============================================================================ -// AVM Module Deployment -// ============================================================================ +@description('Resource ID of the subnet used by the private endpoint.') +param subnetResourceId string + module privateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = { name: take('avm.res.network.private-endpoint.${name}', 64) params: { name: name location: location tags: tags - customNetworkInterfaceName: !empty(customNetworkInterfaceName) ? customNetworkInterfaceName : 'nic-${name}' - subnetResourceId: subnetResourceId + customNetworkInterfaceName: !empty(customNetworkInterfaceName) ? customNetworkInterfaceName : null privateLinkServiceConnections: privateLinkServiceConnections privateDnsZoneGroup: privateDnsZoneGroup + subnetResourceId: subnetResourceId } } -// ============================================================================ -// Outputs -// ============================================================================ @description('Resource ID of the private endpoint.') output resourceId string = privateEndpoint.outputs.resourceId diff --git a/infra/bicep/main.bicep b/infra/bicep/main.bicep index 6a3a3e3c..fb5361d3 100644 --- a/infra/bicep/main.bicep +++ b/infra/bicep/main.bicep @@ -1,12 +1,11 @@ // ============================================================================ -// Main Deployment Template +// main.bicep — Orchestrator +// Description: Pure orchestrator for Content Processing Solution Accelerator +// All resource names are derived from params — no hardcoded names. +// This file only calls modules; no inline resource definitions. // ============================================================================ - targetScope = 'resourceGroup' -metadata name = 'Content Processing Solution Accelerator - Bicep' -metadata description = 'Deploys Content Processing resources using the restored private-repo module interfaces.' - // ============================================================================ // Parameters — Core // ============================================================================ @@ -22,13 +21,10 @@ param solutionUniqueText string = substring(uniqueString(subscription().id, reso @metadata({ azd: { type: 'location' } }) @description('Required. Azure region for all services.') -param location string +param location string = resourceGroup().location @description('Optional. Tags to be applied to the resources.') -param tags object = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} +param tags object = {} @minLength(1) @allowed([ @@ -81,7 +77,7 @@ param gptDeploymentCapacity int = 10 // ============================================================================ @description('Optional. The container registry login server or endpoint for the container images.') -param containerRegistryEndpoint string = '' +param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' @description('Optional. The image tag for the container images.') param imageTag string = 'latest_v2' @@ -122,53 +118,61 @@ param existingFoundryProjectResourceId string = '' // Variables // ============================================================================ -var solutionSuffix = toLower(trim(replace( - replace( - replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), - ' ', - '' - ), - '*', - '' -))) - -var managedIdentityName = 'id-${solutionSuffix}' +var solutionSuffix = toLower(trim(replace(replace(replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', ''))) + +var deployerInfo = deployer() +var createdBy = contains(deployerInfo, 'userPrincipalName') ? split(deployerInfo.userPrincipalName, '@')[0] : deployerInfo.objectId +var existingTags = resourceGroup().tags ?? {} + +// NOTE: managedIdentityName removed — migrated to system-assigned identity + var containerRegistryName = replace('cr${solutionSuffix}', '-', '') + var storageAccountName = take(replace('st${solutionSuffix}', '-', ''), 24) + var cosmosDbName = 'cosmos-${solutionSuffix}' + var cosmosDatabaseName = 'contentprocessing' + var cosmosContainerName = 'documents' + var aiServicesName = 'aif-${solutionSuffix}' + var aiProjectName = 'proj-${solutionSuffix}' -var aiSearchName = 'srch-${solutionSuffix}' + var appConfigurationName = 'appcs-${solutionSuffix}' + var containerAppEnvironmentName = 'cae-${solutionSuffix}' + var contentProcessorAppName = 'ca-${solutionSuffix}-app' + var contentProcessorApiName = 'ca-${solutionSuffix}-api' + var contentProcessorWebName = 'ca-${solutionSuffix}-web' + var contentProcessorWorkflowName = 'ca-${solutionSuffix}-wkfl' + var modelDeploymentName = 'gpt-${solutionSuffix}' + var storageContainerName = 'content' + var storageQueueName = 'content' -var acrPullRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') -var storageBlobDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') -var storageQueueDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88') -var appConfigurationDataReaderRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071') -var cognitiveServicesOpenAiUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd') -var cognitiveServicesUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908') -var azureAiDeveloperRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee') +var effectiveContainerRegistryEndpoint = empty(containerRegistryEndpoint) ? container_registry.outputs.loginServer : containerRegistryEndpoint +var useExternalRegistry = !empty(containerRegistryEndpoint) -var effectiveContainerRegistryEndpoint = empty(containerRegistryEndpoint) ? containerRegistry.outputs.loginServer : containerRegistryEndpoint -var apiAppFqdn = '${contentProcessorApiName}.${containerAppEnvironment.outputs.defaultDomain}' -var webAppFqdn = '${contentProcessorWebName}.${containerAppEnvironment.outputs.defaultDomain}' -var workflowAppFqdn = '${contentProcessorWorkflowName}.${containerAppEnvironment.outputs.defaultDomain}' -var cosmosDbEndpoint = cosmosDBModule.outputs.endpoint +var apiAppFqdn = '${contentProcessorApiName}.${container_app_environment.outputs.defaultDomain}' + +var webAppFqdn = '${contentProcessorWebName}.${container_app_environment.outputs.defaultDomain}' + +var workflowAppFqdn = '${contentProcessorWorkflowName}.${container_app_environment.outputs.defaultDomain}' + +var cosmosDbEndpoint = cosmos_db.outputs.endpoint var sharedEnv = [ { name: 'APP_CONFIG_ENDPOINT' - value: appConfiguration.outputs.endpoint + value: app_configuration.outputs.endpoint } { name: 'APP_ENV' @@ -184,7 +188,7 @@ var sharedEnv = [ } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: enableMonitoring ? appInsights!.outputs.connectionString : '' + value: enableMonitoring ? app_insights!.outputs.connectionString : '' } ] @@ -227,7 +231,7 @@ var apiProbes = [ var appConfigurationValues = [ { name: 'APP_AZURE_OPENAI_ENDPOINT' - value: aiFoundry.outputs.endpoint + value: ai_foundry.outputs.endpoint } { name: 'APP_AZURE_OPENAI_MODEL' @@ -235,11 +239,11 @@ var appConfigurationValues = [ } { name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT' - value: aiFoundry.outputs.endpoint + value: ai_foundry.outputs.endpoint } { name: 'APP_AI_PROJECT_ENDPOINT' - value: aiProject.properties.endpoints['AI Foundry API'] + value: ai_foundry.outputs.projectEndpoint } { name: 'APP_COSMOS_DB_ENDPOINT' @@ -255,28 +259,20 @@ var appConfigurationValues = [ } { name: 'APP_STORAGE_ACCOUNT_NAME' - value: storageAccount.outputs.name + value: storage_account.outputs.name } { name: 'APP_STORAGE_BLOB_ENDPOINT' - value: storageAccount.outputs.blobEndpoint + value: storage_account.outputs.blobEndpoint } { name: 'APP_STORAGE_QUEUE_ENDPOINT' - value: storageAccount.outputs.serviceEndpoints.queue + value: storage_account.outputs.serviceEndpoints.queue } { name: 'APP_STORAGE_CONTAINER_NAME' value: storageContainerName } - { - name: 'APP_AI_SEARCH_ENDPOINT' - value: aiSearch.outputs.endpoint - } - { - name: 'APP_AI_SEARCH_INDEX' - value: 'content-index' - } { name: 'APP_WORKFLOW_APP_ENDPOINT' value: 'https://${workflowAppFqdn}' @@ -295,69 +291,83 @@ var appConfigurationValues = [ } ] +var resourceTags = union(existingTags, tags, { + TemplateName: 'Content Processing' + CreatedBy: createdBy + DeploymentName: deployment().name + Type: 'Non-WAF' +}) + // ============================================================================ -// Module — Monitoring — Log Analytics +// Resource Group Tags // ============================================================================ -module logAnalytics './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { - name: take('module.log-analytics.${solutionSuffix}', 64) - params: { - solutionName: solutionSuffix - location: location - tags: tags +resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { + name: 'default' + properties: { + tags: resourceTags } } // ============================================================================ -// Module — Monitoring — Application Insights +// Module: Monitoring // ============================================================================ -module appInsights './modules/monitoring/app-insights.bicep' = if (enableMonitoring) { - name: take('module.app-insights.${solutionSuffix}', 64) +module log_analytics './modules/monitoring/log-analytics.bicep' = if (enableMonitoring) { + name: take('module.log-analytics.${solutionName}', 64) params: { solutionName: solutionSuffix location: location - workspaceResourceId: logAnalytics!.outputs.resourceId tags: tags } } -// ============================================================================ -// Module — Identity — Managed Identity -// ============================================================================ - -module managedIdentity './modules/identity/managed-identity.bicep' = { - name: take('module.managed-identity.${solutionSuffix}', 64) +module app_insights './modules/monitoring/app-insights.bicep' = if (enableMonitoring) { + name: take('module.app-insights.${solutionName}', 64) params: { solutionName: solutionSuffix - identityName: managedIdentityName location: location + workspaceResourceId: log_analytics!.outputs.resourceId tags: tags } } // ============================================================================ -// Module — Compute — Container Registry +// Module: AI Services // ============================================================================ -module containerRegistry './modules/compute/container-registry.bicep' = { - name: take('module.container-registry.${solutionSuffix}', 64) +module ai_foundry './modules/ai/ai-foundry.bicep' = { + name: take('module.ai-foundry.${solutionName}', 64) params: { - solutionName: solutionSuffix - name: containerRegistryName - location: location - sku: enableRedundancy ? 'Premium' : 'Standard' + name: aiServicesName + location: azureAiServiceLocation + principalIds: [] publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' - tags: tags + projectName: aiProjectName + tags: union(tags, { + location: azureAiServiceLocation + }) + } +} + +module model_deployment './modules/ai/ai-foundry-model-deployment.bicep' = { + name: take('module.model-deployment.${solutionName}', 64) + params: { + aiServicesAccountName: ai_foundry.outputs.name + deploymentName: modelDeploymentName + modelName: gptModelName + modelVersion: gptModelVersion + skuName: deploymentType + skuCapacity: gptDeploymentCapacity } } // ============================================================================ -// Module — Data — Storage Account +// Module: Data // ============================================================================ -module storageAccount './modules/data/storage-account.bicep' = { - name: take('module.storage-account.${solutionSuffix}', 64) +module storage_account './modules/data/storage-account.bicep' = { + name: take('module.storage-account.${solutionName}', 64) params: { solutionName: solutionSuffix name: storageAccountName @@ -369,34 +379,15 @@ module storageAccount './modules/data/storage-account.bicep' = { publicAccess: 'None' } ] + queues: [ + storageQueueName + ] tags: tags } } -// ============================================================================ -// Resources — Storage Queue -// ============================================================================ - -resource storageAccountResource 'Microsoft.Storage/storageAccounts@2025-08-01' existing = { - name: storageAccountName -} - -resource queueService 'Microsoft.Storage/storageAccounts/queueServices@2025-08-01' = { - parent: storageAccountResource - name: 'default' -} - -resource storageQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@2025-08-01' = { - parent: queueService - name: storageQueueName -} - -// ============================================================================ -// Resources — Cosmos DB -// ============================================================================ - -module cosmosDBModule './modules/data/cosmos-db-mongo.bicep' = { - name: take('module.cosmos-db-mongo.${solutionSuffix}', 64) +module cosmos_db './modules/data/cosmos-db-mongo.bicep' = { + name: take('module.cosmos-db-mongo.${solutionName}', 64) params: { solutionName: solutionSuffix name: cosmosDbName @@ -420,119 +411,53 @@ module cosmosDBModule './modules/data/cosmos-db-mongo.bicep' = { } } -// ============================================================================ -// Module — AI — AI Foundry -// ============================================================================ - -module aiFoundry './modules/ai/ai-foundry.bicep' = { - name: take('module.ai-foundry.${solutionSuffix}', 64) - params: { - name: aiServicesName - location: azureAiServiceLocation - principalIds: [] - publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' - tags: union(tags, { - location: azureAiServiceLocation - }) - } -} - -// ============================================================================ -// Resources — AI Project -// ============================================================================ - -resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { - name: aiServicesName -} - -resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = { - parent: aiServicesAccount - name: aiProjectName - location: azureAiServiceLocation - kind: 'AIServices' - identity: { - type: 'SystemAssigned' - } - tags: union(tags, { - location: azureAiServiceLocation - }) - properties: {} -} - -// ============================================================================ -// Module — AI — Model Deployment -// ============================================================================ - -module modelDeployment './modules/ai/ai-foundry-model-deployment.bicep' = { - name: take('module.model-deployment.${solutionSuffix}', 64) - params: { - aiServicesAccountName: aiFoundry.outputs.name - deploymentName: modelDeploymentName - modelName: gptModelName - modelVersion: gptModelVersion - skuName: deploymentType - skuCapacity: gptDeploymentCapacity - } -} - -// ============================================================================ -// Module — AI — Search -// ============================================================================ - -module aiSearch './modules/ai/ai-search.bicep' = { - name: take('module.ai-search.${solutionSuffix}', 64) +module app_configuration './modules/data/app-configuration.bicep' = { + name: take('module.app-configuration.${solutionName}', 64) params: { solutionName: solutionSuffix - name: aiSearchName + name: appConfigurationName location: location - replicaCount: enableRedundancy ? 2 : 1 - partitionCount: enableScalability ? 2 : 1 - publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + keyValues: appConfigurationValues tags: tags } } // ============================================================================ -// Module — Compute — Container App Environment +// Module: Compute +// NOTE: Migrated from user-assigned to system-assigned managed identity. +// Container Apps use their system-assigned identity for ACR pull and role assignments. // ============================================================================ -module containerAppEnvironment './modules/compute/container-app-environment.bicep' = { - name: take('module.container-app-environment.${solutionSuffix}', 64) +module container_registry './modules/compute/container-registry.bicep' = { + name: take('module.container-registry.${solutionName}', 64) params: { solutionName: solutionSuffix - name: containerAppEnvironmentName + name: containerRegistryName location: location - logAnalyticsWorkspaceResourceId: enableMonitoring ? logAnalytics!.outputs.resourceId : '' - zoneRedundant: enableRedundancy + sku: enableRedundancy || enablePrivateNetworking ? 'Premium' : 'Standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' tags: tags } } -// ============================================================================ -// Module — Data — App Configuration -// ============================================================================ - -module appConfiguration './modules/data/app-configuration.bicep' = { - name: take('module.app-configuration.${solutionSuffix}', 64) +module container_app_environment './modules/compute/container-app-environment.bicep' = { + name: take('module.container-app-environment.${solutionName}', 64) params: { solutionName: solutionSuffix - name: appConfigurationName + name: containerAppEnvironmentName location: location - keyValues: appConfigurationValues + logAnalyticsWorkspaceResourceId: enableMonitoring ? log_analytics!.outputs.resourceId : '' + zoneRedundant: enableRedundancy tags: tags } } -// ============================================================================ -// Module — Compute — Content Processor App -// ============================================================================ - -module contentProcessorApp './modules/compute/container-app.bicep' = { - name: take('module.content-processor-app.${solutionSuffix}', 64) +module container_app_processor './modules/compute/container-app.bicep' = { + name: take('module.content-processor-app.${solutionName}', 64) params: { name: contentProcessorAppName location: location - environmentResourceId: containerAppEnvironment.outputs.resourceId + environmentResourceId: container_app_environment.outputs.resourceId disableIngress: true containers: [ { @@ -552,14 +477,11 @@ module contentProcessorApp './modules/compute/container-app.bicep' = { ] managedIdentities: { systemAssigned: true - userAssignedResourceIds: [ - managedIdentity.outputs.resourceId - ] } - registries: [ + registries: useExternalRegistry ? null : [ { server: effectiveContainerRegistryEndpoint - identity: managedIdentity.outputs.resourceId + identity: 'system' } ] scaleSettings: { @@ -570,16 +492,12 @@ module contentProcessorApp './modules/compute/container-app.bicep' = { } } -// ============================================================================ -// Module — Compute — Content Processor API -// ============================================================================ - -module contentProcessorApi './modules/compute/container-app.bicep' = { - name: take('module.content-processor-api.${solutionSuffix}', 64) +module container_app_api './modules/compute/container-app.bicep' = { + name: take('module.content-processor-api.${solutionName}', 64) params: { name: contentProcessorApiName location: location - environmentResourceId: containerAppEnvironment.outputs.resourceId + environmentResourceId: container_app_environment.outputs.resourceId ingressExternal: true ingressTargetPort: 80 containers: [ @@ -601,14 +519,11 @@ module contentProcessorApi './modules/compute/container-app.bicep' = { ] managedIdentities: { systemAssigned: true - userAssignedResourceIds: [ - managedIdentity.outputs.resourceId - ] } - registries: [ + registries: useExternalRegistry ? null : [ { server: effectiveContainerRegistryEndpoint - identity: managedIdentity.outputs.resourceId + identity: 'system' } ] scaleSettings: { @@ -619,16 +534,12 @@ module contentProcessorApi './modules/compute/container-app.bicep' = { } } -// ============================================================================ -// Module — Compute — Content Processor Web -// ============================================================================ - -module contentProcessorWeb './modules/compute/container-app.bicep' = { - name: take('module.content-processor-web.${solutionSuffix}', 64) +module container_app_web './modules/compute/container-app.bicep' = { + name: take('module.content-processor-web.${solutionName}', 64) params: { name: contentProcessorWebName location: location - environmentResourceId: containerAppEnvironment.outputs.resourceId + environmentResourceId: container_app_environment.outputs.resourceId ingressExternal: true ingressTargetPort: 80 containers: [ @@ -653,14 +564,11 @@ module contentProcessorWeb './modules/compute/container-app.bicep' = { ] managedIdentities: { systemAssigned: true - userAssignedResourceIds: [ - managedIdentity.outputs.resourceId - ] } - registries: [ + registries: useExternalRegistry ? null : [ { server: effectiveContainerRegistryEndpoint - identity: managedIdentity.outputs.resourceId + identity: 'system' } ] corsPolicy: { @@ -686,16 +594,12 @@ module contentProcessorWeb './modules/compute/container-app.bicep' = { } } -// ============================================================================ -// Module — Compute — Content Processor Workflow -// ============================================================================ - -module contentProcessorWorkflow './modules/compute/container-app.bicep' = { - name: take('module.content-processor-workflow.${solutionSuffix}', 64) +module container_app_workflow './modules/compute/container-app.bicep' = { + name: take('module.content-processor-workflow.${solutionName}', 64) params: { name: contentProcessorWorkflowName location: location - environmentResourceId: containerAppEnvironment.outputs.resourceId + environmentResourceId: container_app_environment.outputs.resourceId ingressExternal: true ingressTargetPort: 80 containers: [ @@ -716,14 +620,11 @@ module contentProcessorWorkflow './modules/compute/container-app.bicep' = { ] managedIdentities: { systemAssigned: true - userAssignedResourceIds: [ - managedIdentity.outputs.resourceId - ] } - registries: [ + registries: useExternalRegistry ? null : [ { server: effectiveContainerRegistryEndpoint - identity: managedIdentity.outputs.resourceId + identity: 'system' } ] scaleSettings: { @@ -735,205 +636,64 @@ module contentProcessorWorkflow './modules/compute/container-app.bicep' = { } // ============================================================================ -// Resources — Existing Resource References +// Module: Identity (Role Assignments) // ============================================================================ -resource containerRegistryResource 'Microsoft.ContainerRegistry/registries@2025-04-01' existing = { - name: containerRegistryName -} - -resource appConfigurationResource 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = { - name: appConfigurationName +module role_assignments './modules/identity/role-assignments.bicep' = { + name: take('module.role-assignments.${solutionName}', 64) + params: { + solutionName: solutionSuffix + containerRegistryName: containerRegistryName + storageAccountName: storageAccountName + appConfigurationName: appConfigurationName + aiServicesName: ai_foundry.outputs.name + managedIdentityPrincipalId: container_app_processor.outputs.principalId + contentProcessorAppPrincipalId: container_app_processor.outputs.principalId + contentProcessorApiPrincipalId: container_app_api.outputs.principalId + contentProcessorWebPrincipalId: container_app_web.outputs.principalId + contentProcessorWorkflowPrincipalId: container_app_workflow.outputs.principalId + } } // ============================================================================ -// Resources — Role Assignments +// Outputs // ============================================================================ -resource acrPullAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(containerRegistryName, managedIdentityName, 'acr-pull') - scope: containerRegistryResource - properties: { - principalId: managedIdentity.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: acrPullRoleId - } -} - -resource contentProcessorBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(storageAccountName, contentProcessorAppName, 'blob') - scope: storageAccountResource - properties: { - principalId: contentProcessorApp.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: storageBlobDataContributorRoleId - } -} - -resource contentProcessorApiBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(storageAccountName, contentProcessorApiName, 'blob') - scope: storageAccountResource - properties: { - principalId: contentProcessorApi.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: storageBlobDataContributorRoleId - } -} - -resource contentProcessorWorkflowBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(storageAccountName, contentProcessorWorkflowName, 'blob') - scope: storageAccountResource - properties: { - principalId: contentProcessorWorkflow.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: storageBlobDataContributorRoleId - } -} - -resource contentProcessorQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(storageAccountName, contentProcessorAppName, 'queue') - scope: storageAccountResource - properties: { - principalId: contentProcessorApp.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: storageQueueDataContributorRoleId - } -} - -resource contentProcessorApiQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(storageAccountName, contentProcessorApiName, 'queue') - scope: storageAccountResource - properties: { - principalId: contentProcessorApi.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: storageQueueDataContributorRoleId - } -} - -resource contentProcessorWorkflowQueueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(storageAccountName, contentProcessorWorkflowName, 'queue') - scope: storageAccountResource - properties: { - principalId: contentProcessorWorkflow.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: storageQueueDataContributorRoleId - } -} +@description('The solution name.') +output SOLUTION_NAME string = solutionName -resource contentProcessorAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(appConfigurationName, contentProcessorAppName, 'appconfig') - scope: appConfigurationResource - properties: { - principalId: contentProcessorApp.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: appConfigurationDataReaderRoleId - } -} +@description('The name of the Container App used for Web App.') +output CONTAINER_WEB_APP_NAME string = container_app_web.outputs.name -resource contentProcessorApiAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(appConfigurationName, contentProcessorApiName, 'appconfig') - scope: appConfigurationResource - properties: { - principalId: contentProcessorApi.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: appConfigurationDataReaderRoleId - } -} +@description('The name of the Container App used for API.') +output CONTAINER_API_APP_NAME string = container_app_api.outputs.name -resource contentProcessorWebAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(appConfigurationName, contentProcessorWebName, 'appconfig') - scope: appConfigurationResource - properties: { - principalId: contentProcessorWeb.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: appConfigurationDataReaderRoleId - } -} +@description('The FQDN of the Container App Web.') +output CONTAINER_WEB_APP_FQDN string = webAppFqdn -resource contentProcessorWorkflowAppConfigRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(appConfigurationName, contentProcessorWorkflowName, 'appconfig') - scope: appConfigurationResource - properties: { - principalId: contentProcessorWorkflow.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: appConfigurationDataReaderRoleId - } -} +@description('The FQDN of the Container App API.') +output CONTAINER_API_APP_FQDN string = apiAppFqdn -resource contentProcessorOpenAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(aiServicesName, contentProcessorAppName, 'openai-user') - scope: aiServicesAccount - properties: { - principalId: contentProcessorApp.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: cognitiveServicesOpenAiUserRoleId - } -} +@description('The name of the Container App used for APP.') +output CONTAINER_APP_NAME string = container_app_processor.outputs.name -resource contentProcessorWorkflowOpenAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(aiServicesName, contentProcessorWorkflowName, 'openai-user') - scope: aiServicesAccount - properties: { - principalId: contentProcessorWorkflow.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: cognitiveServicesOpenAiUserRoleId - } -} +@description('The name of the Container App used for Workflow.') +output CONTAINER_WORKFLOW_APP_NAME string = container_app_workflow.outputs.name -resource contentProcessorAiDeveloperAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(aiServicesName, contentProcessorAppName, 'ai-developer') - scope: aiServicesAccount - properties: { - principalId: contentProcessorApp.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: azureAiDeveloperRoleId - } -} +@description('The system-assigned identity resource ID used for the Container App.') +output CONTAINER_APP_USER_IDENTITY_ID string = container_app_processor.outputs.resourceId -resource contentProcessorWorkflowAiDeveloperAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(aiServicesName, contentProcessorWorkflowName, 'ai-developer') - scope: aiServicesAccount - properties: { - principalId: contentProcessorWorkflow.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: azureAiDeveloperRoleId - } -} +@description('The system-assigned identity Principal ID used for the Container App.') +output CONTAINER_APP_USER_PRINCIPAL_ID string = container_app_processor.outputs.principalId -resource contentProcessorAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(aiServicesName, contentProcessorAppName, 'cog-user') - scope: aiServicesAccount - properties: { - principalId: contentProcessorApp.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: cognitiveServicesUserRoleId - } -} +@description('The name of the Azure Container Registry.') +output CONTAINER_REGISTRY_NAME string = container_registry.outputs.name -resource contentProcessorWorkflowAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(aiServicesName, contentProcessorWorkflowName, 'cog-user') - scope: aiServicesAccount - properties: { - principalId: contentProcessorWorkflow.outputs.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: cognitiveServicesUserRoleId - } -} +@description('The login server of the Azure Container Registry.') +output CONTAINER_REGISTRY_LOGIN_SERVER string = container_registry.outputs.loginServer -// ============================================================================ -// Outputs -// ============================================================================ +@description('The name of the AI Services account that hosts both Azure OpenAI and Content Understanding.') +output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = ai_foundry.outputs.name -output SOLUTION_NAME string = solutionName -output CONTAINER_WEB_APP_NAME string = contentProcessorWeb.outputs.name -output CONTAINER_API_APP_NAME string = contentProcessorApi.outputs.name -output CONTAINER_WEB_APP_FQDN string = webAppFqdn -output CONTAINER_API_APP_FQDN string = apiAppFqdn -output CONTAINER_APP_NAME string = contentProcessorApp.outputs.name -output CONTAINER_WORKFLOW_APP_NAME string = contentProcessorWorkflow.outputs.name -output CONTAINER_APP_USER_IDENTITY_ID string = managedIdentity.outputs.resourceId -output CONTAINER_APP_USER_PRINCIPAL_ID string = managedIdentity.outputs.principalId -output CONTAINER_REGISTRY_NAME string = containerRegistry.outputs.name -output CONTAINER_REGISTRY_LOGIN_SERVER string = containerRegistry.outputs.loginServer -output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = aiFoundry.outputs.name +@description('The resource group the resources were deployed into.') output AZURE_RESOURCE_GROUP string = resourceGroup().name diff --git a/infra/bicep/main.json b/infra/bicep/main.json index 53cee80f..abe621cd 100644 --- a/infra/bicep/main.json +++ b/infra/bicep/main.json @@ -5,82 +5,179 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "6422306545253132015" - }, - "name": "Content Processing Solution Accelerator - Bicep", - "description": "Deploys Content Processing resources using the restored private-repo module interfaces." + "templateHash": "10242238019010929374" + } }, "parameters": { "solutionName": { "type": "string", "defaultValue": "cps", "minLength": 3, - "maxLength": 20 + "maxLength": 20, + "metadata": { + "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources." + } }, "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { "azd": { "type": "location" - } + }, + "description": "Required. Azure region for all services." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." } }, "azureAiServiceLocation": { "type": "string", + "allowedValues": [ + "australiaeast", + "eastus", + "eastus2", + "japaneast", + "southcentralus", + "southeastasia", + "swedencentral", + "uksouth", + "westeurope", + "westus", + "westus3" + ], "metadata": { "azd": { - "type": "location" - } + "type": "location", + "usageName": [ + "OpenAI.GlobalStandard.gpt-5.1,300" + ] + }, + "description": "Required. Location for the Azure AI Services deployment." + }, + "minLength": 1 + }, + "deploymentType": { + "type": "string", + "defaultValue": "GlobalStandard", + "allowedValues": [ + "Standard", + "GlobalStandard" + ], + "metadata": { + "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." } }, "gptModelName": { "type": "string", - "defaultValue": "gpt-5.1" + "defaultValue": "gpt-5.1", + "metadata": { + "description": "Optional. Name of the GPT model to deploy." + } + }, + "gptModelVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Version of the GPT model to deploy. Empty string uses the latest available version." + } + }, + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. Capacity of the GPT deployment." + } }, "containerRegistryEndpoint": { "type": "string", - "defaultValue": "" + "defaultValue": "cpscontainerreg.azurecr.io", + "metadata": { + "description": "Optional. The container registry login server or endpoint for the container images." + } }, "imageTag": { "type": "string", - "defaultValue": "latest_v2" + "defaultValue": "latest_v2", + "metadata": { + "description": "Optional. The image tag for the container images." + } }, "enablePrivateNetworking": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable private networking for the deployment." + } }, "enableMonitoring": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources." + } }, "enableRedundancy": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources." + } }, "enableScalability": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable scalability for applicable resources." + } }, "enableTelemetry": { "type": "bool", - "defaultValue": true + "defaultValue": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the deployment." + } }, "enablePurgeProtection": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable purge protection." + } }, - "tags": { - "type": "object", - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Existing Log Analytics Workspace resource ID." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Existing Azure AI Foundry project resource ID." } } }, "variables": { - "uniqueToken": "[substring(uniqueString(subscription().subscriptionId, resourceGroup().id, parameters('solutionName')), 0, 5)]", - "solutionSuffix": "[toLower(replace(replace(replace(format('{0}{1}', parameters('solutionName'), variables('uniqueToken')), '-', ''), '_', ''), '.', ''))]", - "managedIdentityName": "[format('id-{0}', variables('solutionSuffix'))]", + "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", + "deployerInfo": "[deployer()]", + "createdBy": "[if(contains(variables('deployerInfo'), 'userPrincipalName'), split(variables('deployerInfo').userPrincipalName, '@')[0], variables('deployerInfo').objectId)]", + "existingTags": "[coalesce(resourceGroup().tags, createObject())]", "containerRegistryName": "[replace(format('cr{0}', variables('solutionSuffix')), '-', '')]", "storageAccountName": "[take(replace(format('st{0}', variables('solutionSuffix')), '-', ''), 24)]", "cosmosDbName": "[format('cosmos-{0}', variables('solutionSuffix'))]", @@ -88,7 +185,6 @@ "cosmosContainerName": "documents", "aiServicesName": "[format('aif-{0}', variables('solutionSuffix'))]", "aiProjectName": "[format('proj-{0}', variables('solutionSuffix'))]", - "aiSearchName": "[format('srch-{0}', variables('solutionSuffix'))]", "appConfigurationName": "[format('appcs-{0}', variables('solutionSuffix'))]", "containerAppEnvironmentName": "[format('cae-{0}', variables('solutionSuffix'))]", "contentProcessorAppName": "[format('ca-{0}-app', variables('solutionSuffix'))]", @@ -98,14 +194,7 @@ "modelDeploymentName": "[format('gpt-{0}', variables('solutionSuffix'))]", "storageContainerName": "content", "storageQueueName": "content", - "acrPullRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", - "storageBlobDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "storageQueueDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "appConfigurationDataReaderRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "cognitiveServicesOpenAiUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "cognitiveServicesUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "azureAiDeveloperRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "cosmosDbEndpoint": "[format('https://{0}.mongo.cosmos.azure.com:443/', variables('cosmosDbName'))]", + "useExternalRegistry": "[not(empty(parameters('containerRegistryEndpoint')))]", "apiProbes": [ { "type": "Liveness", @@ -140,347 +229,23 @@ "periodSeconds": 5, "failureThreshold": 10 } - ] + ], + "resourceTags": "[union(variables('existingTags'), parameters('tags'), createObject('TemplateName', 'Content Processing', 'CreatedBy', variables('createdBy'), 'DeploymentName', deployment().name, 'Type', 'Non-WAF'))]" }, "resources": [ { - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-08-01", - "name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]" - }, - { - "type": "Microsoft.Storage/storageAccounts/queueServices/queues", - "apiVersion": "2025-08-01", - "name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', variables('storageQueueName'))]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageAccountName'), 'default')]" - ] - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2023-04-15", - "name": "[variables('cosmosDbName')]", - "location": "[parameters('location')]", - "kind": "MongoDB", - "tags": "[parameters('tags')]", + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", "properties": { - "databaseAccountOfferType": "Standard", - "locations": [ - { - "locationName": "[parameters('location')]", - "failoverPriority": 0, - "isZoneRedundant": "[parameters('enableRedundancy')]" - } - ], - "capabilities": [ - { - "name": "EnableMongo" - } - ], - "apiProperties": { - "serverVersion": "7.0" - }, - "disableLocalAuth": false, - "enableAutomaticFailover": false, - "enableMultipleWriteLocations": false, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]" + "tags": "[variables('resourceTags')]" } }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", - "apiVersion": "2023-04-15", - "name": "[format('{0}/{1}', variables('cosmosDbName'), variables('cosmosDatabaseName'))]", - "properties": { - "resource": { - "id": "[variables('cosmosDatabaseName')]" - }, - "options": {} - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]" - ] - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", - "apiVersion": "2023-04-15", - "name": "[format('{0}/{1}/{2}', variables('cosmosDbName'), variables('cosmosDatabaseName'), variables('cosmosContainerName'))]", - "properties": { - "resource": { - "id": "[variables('cosmosContainerName')]", - "shardKey": { - "id": "Hash" - }, - "indexes": [ - { - "key": { - "keys": [ - "_id" - ] - } - } - ] - }, - "options": {} - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', variables('cosmosDbName'), variables('cosmosDatabaseName'))]" - ] - }, - { - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', variables('aiServicesName'), variables('aiProjectName'))]", - "location": "[parameters('azureAiServiceLocation')]", - "kind": "AIServices", - "identity": { - "type": "SystemAssigned" - }, - "tags": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]", - "properties": {} - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', variables('containerRegistryName'))]", - "name": "[guid(variables('containerRegistryName'), variables('managedIdentityName'), 'acr-pull')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('acrPullRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'blob')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'blob')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'blob')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'queue')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'queue')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'queue')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorAppName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorApiName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWebName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWorkflowName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'openai-user')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'openai-user')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'ai-developer')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'ai-developer')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'cog-user')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'cog-user')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, { "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.log-analytics.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -601,7 +366,7 @@ "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.app-insights.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -615,7 +380,7 @@ "value": "[parameters('location')]" }, "workspaceResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "tags": { "value": "[parameters('tags')]" @@ -628,7 +393,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4667471246975862151" + "templateHash": "12837854244259197798" } }, "parameters": { @@ -691,6 +456,13 @@ "metadata": { "description": "Flow type for Application Insights." } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Kind of Application Insights resource." + } } }, "resources": [ @@ -700,7 +472,7 @@ "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "kind": "web", + "kind": "[parameters('kind')]", "properties": { "Application_Type": "[parameters('applicationType')]", "Flow_Type": "[parameters('flowType')]", @@ -752,30 +524,34 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "identityName": { - "value": "[variables('managedIdentityName')]" + "name": { + "value": "[variables('aiServicesName')]" }, "location": { - "value": "[parameters('location')]" + "value": "[parameters('azureAiServiceLocation')]" + }, + "principalIds": { + "value": [] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "projectName": { + "value": "[variables('aiProjectName')]" }, "tags": { - "value": "[parameters('tags')]" + "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" } }, "template": { @@ -785,74 +561,160 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "14165903959794426055" + "templateHash": "8636926699738224009" } }, "parameters": { - "solutionName": { + "name": { "type": "string", "metadata": { - "description": "Solution name used for resource naming." + "description": "Required. Name of the AI Services account." } }, - "identityName": { + "location": { "type": "string", - "defaultValue": "[format('id-{0}', parameters('solutionName'))]", "metadata": { - "description": "Name of the managed identity." + "description": "Required. Azure region for the resource." } }, - "location": { + "principalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." + } + }, + "publicNetworkAccess": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Azure region for the resource." + "description": "Optional. Whether public network access is allowed." } }, "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Tags to apply to the resource." + "description": "Optional. Tags to apply to the resource." + } + }, + "projectName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the AI Foundry project to create. If empty, no project is created." } } }, + "variables": { + "shouldCreateProject": "[not(empty(parameters('projectName')))]" + }, "resources": [ { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[parameters('identityName')]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]", "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the managed identity." + "tags": "[parameters('tags')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]" - }, - "principalId": { + "sku": { + "name": "S0" + }, + "properties": { + "customSubDomainName": "[parameters('name')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "disableLocalAuth": true, + "allowProjectManagement": true, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" + } + } + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principalIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", + "properties": { + "principalId": "[parameters('principalIds')[copyIndex()]]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] + }, + { + "condition": "[variables('shouldCreateProject')]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('projectName'))]", + "location": "[parameters('location')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "tags": "[parameters('tags')]", + "properties": {}, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Principal ID (object ID) of the managed identity." + "description": "The name of the deployed AI Services account." }, - "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').principalId]" + "value": "[parameters('name')]" }, - "clientId": { + "resourceId": { "type": "string", "metadata": { - "description": "Client ID of the managed identity." + "description": "The resource ID of the AI Services account." }, - "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').clientId]" + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" }, - "name": { + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the AI Services account." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2025-12-01').endpoint]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system-assigned managed identity." + }, + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2025-12-01', 'full').identity.principalId]" + }, + "projectEndpoint": { + "type": "string", + "metadata": { + "description": "The AI Foundry project endpoint (empty if no project created)." + }, + "value": "[if(variables('shouldCreateProject'), reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('name'), parameters('projectName')), '2025-12-01').endpoints['AI Foundry API'], '')]" + }, + "projectName": { "type": "string", "metadata": { - "description": "Name of the managed identity." + "description": "The name of the AI Foundry project (empty if no project created)." }, - "value": "[parameters('identityName')]" + "value": "[if(variables('shouldCreateProject'), parameters('projectName'), '')]" } } } @@ -861,26 +723,30 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.model-deployment.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" + "aiServicesAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, - "name": { - "value": "[variables('containerRegistryName')]" + "deploymentName": { + "value": "[variables('modelDeploymentName')]" }, - "location": { - "value": "[parameters('location')]" + "modelName": { + "value": "[parameters('gptModelName')]" }, - "sku": "[if(parameters('enableRedundancy'), createObject('value', 'Premium'), createObject('value', 'Standard'))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "tags": { - "value": "[parameters('tags')]" + "modelVersion": { + "value": "[parameters('gptModelVersion')]" + }, + "skuName": { + "value": "[parameters('deploymentType')]" + }, + "skuCapacity": { + "value": "[parameters('gptDeploymentCapacity')]" } }, "template": { @@ -890,103 +756,78 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "17432455227529690473" + "templateHash": "18411757618261752815" } }, "parameters": { - "solutionName": { + "aiServicesAccountName": { "type": "string", "metadata": { - "description": "Solution name used for naming convention." + "description": "Required. Name of the parent AI Services account." } }, - "name": { + "deploymentName": { "type": "string", - "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", "metadata": { - "description": "Name of the container registry." + "description": "Required. Name for this model deployment." } }, - "location": { + "modelFormat": { "type": "string", + "defaultValue": "OpenAI", "metadata": { - "description": "Azure region for deployment." + "description": "Optional. Model format (e.g., OpenAI)." } }, - "tags": { - "type": "object", - "defaultValue": {}, + "modelName": { + "type": "string", "metadata": { - "description": "Resource tags." + "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." } }, - "sku": { + "modelVersion": { "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Standard", - "Premium" - ], + "defaultValue": "", "metadata": { - "description": "SKU for the container registry." + "description": "Optional. Model version. Empty string means latest." } }, - "adminUserEnabled": { - "type": "bool", - "defaultValue": false, + "raiPolicyName": { + "type": "string", + "defaultValue": "Microsoft.Default", "metadata": { - "description": "Enable admin user." + "description": "Optional. RAI policy name." } }, - "publicNetworkAccess": { + "skuName": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], "metadata": { - "description": "Public network access setting." + "description": "Required. SKU name (e.g., Standard, GlobalStandard)." } }, - "exportPolicyStatus": { - "type": "string", - "defaultValue": "enabled", + "skuCapacity": { + "type": "int", "metadata": { - "description": "Export policy status." + "description": "Required. SKU capacity (tokens per minute in thousands)." } } }, "resources": [ { - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", "properties": { - "adminUserEnabled": "[parameters('adminUserEnabled')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "dataEndpointEnabled": false, - "networkRuleBypassOptions": "AzureServices", - "policies": { - "exportPolicy": { - "status": "[parameters('exportPolicyStatus')]" - }, - "retentionPolicy": { - "status": "enabled", - "days": 7 - }, - "trustPolicy": { - "status": "disabled", - "type": "Notary" - } + "model": { + "format": "[parameters('modelFormat')]", + "name": "[parameters('modelName')]", + "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" }, - "zoneRedundancy": "Disabled" + "raiPolicyName": "[parameters('raiPolicyName')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacity": "[parameters('skuCapacity')]" } } ], @@ -994,32 +835,28 @@ "name": { "type": "string", "metadata": { - "description": "The name of the container registry." - }, - "value": "[parameters('name')]" - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "The login server URL." + "description": "Name of the deployed model." }, - "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" + "value": "[parameters('deploymentName')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the container registry." + "description": "Resource ID of the model deployment." }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" } } } - } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64))]" + ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.storage-account.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -1044,6 +881,11 @@ } ] }, + "queues": { + "value": [ + "[variables('storageQueueName')]" + ] + }, "tags": { "value": "[parameters('tags')]" } @@ -1055,7 +897,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "17696053432794478605" + "templateHash": "1152371270983236524" } }, "parameters": { @@ -1124,6 +966,13 @@ "description": "Allow shared key access." } }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable hierarchical namespace (Data Lake Storage Gen2)." + } + }, "containers": { "type": "array", "defaultValue": [ @@ -1135,6 +984,13 @@ "metadata": { "description": "Blob containers to create." } + }, + "queues": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Queue names to create." + } } }, "resources": [ @@ -1154,6 +1010,7 @@ "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", "minimumTlsVersion": "TLS1_2", "supportsHttpsTrafficOnly": true, + "isHnsEnabled": "[parameters('enableHierarchicalNamespace')]", "encryption": { "services": { "blob": { @@ -1190,6 +1047,27 @@ "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('name'), 'default')]" ] + }, + { + "condition": "[not(empty(parameters('queues')))]", + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "storageQueues", + "count": "[length(parameters('queues'))]" + }, + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', parameters('queues')[copyIndex()])]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('name'), 'default')]" + ] } ], "outputs": { @@ -1214,6 +1092,13 @@ }, "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.blob]" }, + "queueEndpoint": { + "type": "string", + "metadata": { + "description": "Primary queue endpoint." + }, + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.queue]" + }, "serviceEndpoints": { "type": "object", "metadata": { @@ -1228,26 +1113,60 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.cosmos-db-mongo.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, "name": { - "value": "[variables('aiServicesName')]" + "value": "[variables('cosmosDbName')]" }, "location": { - "value": "[parameters('azureAiServiceLocation')]" - }, - "principalIds": { - "value": [] + "value": "[parameters('location')]" }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", "tags": { - "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" - } + "value": "[parameters('tags')]" + }, + "databaseName": { + "value": "[variables('cosmosDatabaseName')]" + }, + "collections": { + "value": [ + { + "name": "[variables('cosmosContainerName')]", + "shardKey": { + "id": "Hash" + }, + "indexes": [ + { + "key": { + "keys": [ + "_id" + ] + } + } + ] + } + ] + }, + "serverVersion": { + "value": "7.0" + }, + "consistencyLevel": { + "value": "Session" + }, + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "enableAutomaticFailover": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1256,259 +1175,218 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "7594344478012985364" + "templateHash": "16959142942271052833" } }, "parameters": { - "name": { + "solutionName": { "type": "string", "metadata": { - "description": "Required. Name of the AI Services account." + "description": "Solution name suffix used to derive the resource name." } }, - "location": { + "name": { "type": "string", + "defaultValue": "[format('cosmos-{0}', parameters('solutionName'))]", "metadata": { - "description": "Required. Azure region for the resource." - } - }, - "principalIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." + "description": "Name of the Cosmos DB account." } }, - "publicNetworkAccess": { + "location": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], "metadata": { - "description": "Optional. Whether public network access is allowed." + "description": "Azure region for the resource." } }, "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Optional. Tags to apply to the resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "AIServices", - "identity": { - "type": "SystemAssigned" - }, - "sku": { - "name": "S0" - }, - "properties": { - "customSubDomainName": "[parameters('name')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "disableLocalAuth": true, - "allowProjectManagement": true, - "networkAcls": { - "bypass": "AzureServices", - "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" - } + "description": "Tags to apply to the resource." } }, - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principalIds'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", - "properties": { - "principalId": "[parameters('principalIds')[copyIndex()]]", - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AI Services account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the AI Services account." - }, - "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" - }, - "endpoint": { + "databaseName": { "type": "string", + "defaultValue": "default", "metadata": { - "description": "The endpoint of the AI Services account." - }, - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01').endpoint]" + "description": "MongoDB database name." + } }, - "systemAssignedPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system-assigned managed identity." - }, - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01', 'full').identity.principalId]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-model.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "aiServicesAccountName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" - }, - "deploymentName": { - "value": "[variables('modelDeploymentName')]" - }, - "modelName": { - "value": "[parameters('gptModelName')]" - }, - "skuName": { - "value": "GlobalStandard" - }, - "skuCapacity": { - "value": 10 - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "18411757618261752815" - } - }, - "parameters": { - "aiServicesAccountName": { - "type": "string", + "collections": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. Name of the parent AI Services account." + "description": "MongoDB collections to create." } }, - "deploymentName": { + "serverVersion": { "type": "string", + "defaultValue": "7.0", + "allowedValues": [ + "4.2", + "5.0", + "6.0", + "7.0" + ], "metadata": { - "description": "Required. Name for this model deployment." + "description": "MongoDB server version." } }, - "modelFormat": { + "consistencyLevel": { "type": "string", - "defaultValue": "OpenAI", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], "metadata": { - "description": "Optional. Model format (e.g., OpenAI)." + "description": "Default consistency level." } }, - "modelName": { - "type": "string", + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." + "description": "Enable analytical storage (Synapse Link)." } }, - "modelVersion": { - "type": "string", - "defaultValue": "", + "zoneRedundant": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Model version. Empty string means latest." + "description": "Enable zone redundancy." } }, - "raiPolicyName": { - "type": "string", - "defaultValue": "Microsoft.Default", + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. RAI policy name." + "description": "Enable automatic failover." } }, - "skuName": { + "haLocation": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. SKU name (e.g., Standard, GlobalStandard)." + "description": "HA paired region for multi-region failover." } }, - "skuCapacity": { - "type": "int", + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Required. SKU capacity (tokens per minute in thousands)." + "description": "Public network access setting." } } }, "resources": [ { - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-10-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "MongoDB", "properties": { - "model": { - "format": "[parameters('modelFormat')]", - "name": "[parameters('modelName')]", - "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" + "consistencyPolicy": { + "defaultConsistencyLevel": "[parameters('consistencyLevel')]" }, - "raiPolicyName": "[parameters('raiPolicyName')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacity": "[parameters('skuCapacity')]" + "locations": "[if(and(parameters('zoneRedundant'), not(empty(parameters('haLocation')))), createArray(createObject('locationName', parameters('location'), 'failoverPriority', 0, 'isZoneRedundant', true()), createObject('locationName', parameters('haLocation'), 'failoverPriority', 1, 'isZoneRedundant', true())), createArray(createObject('locationName', parameters('location'), 'failoverPriority', 0, 'isZoneRedundant', parameters('zoneRedundant'))))]", + "databaseAccountOfferType": "Standard", + "enableAutomaticFailover": "[parameters('enableAutomaticFailover')]", + "enableMultipleWriteLocations": false, + "apiProperties": { + "serverVersion": "[parameters('serverVersion')]" + }, + "enableAnalyticalStorage": "[parameters('enableAnalyticalStorage')]", + "capabilities": [ + { + "name": "EnableMongo" + } + ], + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" } + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-10-15", + "name": "[format('{0}/{1}', parameters('name'), parameters('databaseName'))]", + "properties": { + "resource": { + "id": "[parameters('databaseName')]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "mongoCollections", + "count": "[length(parameters('collections'))]" + }, + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-10-15", + "name": "[format('{0}/{1}/{2}', parameters('name'), parameters('databaseName'), parameters('collections')[copyIndex()].name)]", + "properties": { + "resource": { + "id": "[parameters('collections')[copyIndex()].name]", + "shardKey": "[coalesce(tryGet(parameters('collections')[copyIndex()], 'shardKey'), createObject())]", + "indexes": "[coalesce(tryGet(parameters('collections')[copyIndex()], 'indexes'), createArray(createObject('key', createObject('keys', createArray('_id')))))]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('name'), parameters('databaseName'))]" + ] } ], "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Cosmos DB account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "Name of the deployed model." + "description": "Name of the Cosmos DB account." }, - "value": "[parameters('deploymentName')]" + "value": "[parameters('name')]" }, - "resourceId": { + "connectionString": { "type": "string", "metadata": { - "description": "Resource ID of the model deployment." + "description": "MongoDB connection string (without credentials — use Key Vault for secrets)." }, - "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" + "value": "[format('mongodb+srv://{0}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000', parameters('name'))]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint of the Cosmos DB account." + }, + "value": "[format('https://{0}.mongo.cosmos.azure.com:443/', parameters('name'))]" + }, + "databaseName": { + "type": "string", + "metadata": { + "description": "Database name." + }, + "value": "[parameters('databaseName')]" } } } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]" - ] + } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.app-configuration.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -1519,14 +1397,75 @@ "value": "[variables('solutionSuffix')]" }, "name": { - "value": "[variables('aiSearchName')]" + "value": "[variables('appConfigurationName')]" }, "location": { "value": "[parameters('location')]" }, - "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", - "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.projectEndpoint.value]" + }, + { + "name": "APP_COSMOS_DB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_DB_NAME", + "value": "[variables('cosmosDatabaseName')]" + }, + { + "name": "APP_COSMOS_DB_CONTAINER", + "value": "[variables('cosmosContainerName')]" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "APP_STORAGE_BLOB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.blobEndpoint.value]" + }, + { + "name": "APP_STORAGE_QUEUE_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_STORAGE_CONTAINER_NAME", + "value": "[variables('storageContainerName')]" + }, + { + "name": "APP_WORKFLOW_APP_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "APP_API_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + } + ] + }, "tags": { "value": "[parameters('tags')]" } @@ -1538,22 +1477,21 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "714050788324647491" + "templateHash": "17000481054877854952" } }, "parameters": { "solutionName": { "type": "string", - "minLength": 3, "metadata": { - "description": "Solution name suffix used to derive the resource name." + "description": "Solution name used for naming convention." } }, "name": { "type": "string", - "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", "metadata": { - "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + "description": "Name of the App Configuration store." } }, "location": { @@ -1569,302 +1507,99 @@ "description": "Tags to apply to the resource." } }, - "skuName": { - "type": "string", - "defaultValue": "basic", - "allowedValues": [ - "free", - "basic", - "standard", - "standard2", - "standard3", - "storage_optimized_l1", - "storage_optimized_l2" - ], - "metadata": { - "description": "SKU name for the search service." - } - }, - "replicaCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of replicas." - } - }, - "partitionCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of partitions." - } - }, - "hostingMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "HighDensity" - ], - "metadata": { - "description": "Hosting mode." - } - }, - "semanticSearch": { + "sku": { "type": "string", - "defaultValue": "free", + "defaultValue": "Standard", "allowedValues": [ - "disabled", - "free", - "standard" + "Free", + "Standard" ], "metadata": { - "description": "Semantic search tier." + "description": "SKU for the configuration store." } }, "disableLocalAuth": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Whether to disable local authentication." - } - }, - "managedIdentityType": { - "type": "string", - "defaultValue": "SystemAssigned", + "defaultValue": false, "metadata": { - "description": "Managed identity type for the search service." + "description": "Disable local (key-based) authentication." } }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", + "keyValues": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Public network access setting." + "description": "Key-value pairs to store in the configuration." } } }, "resources": [ { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2023-03-01", "name": "[parameters('name')]", "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "sku": { - "name": "[parameters('skuName')]" - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "searchServiceUpdate", + "name": "[parameters('sku')]" + }, "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "skuName": { - "value": "[parameters('skuName')]" - }, - "replicaCount": { - "value": "[parameters('replicaCount')]" - }, - "partitionCount": { - "value": "[parameters('partitionCount')]" - }, - "hostingMode": { - "value": "[parameters('hostingMode')]" - }, - "semanticSearch": { - "value": "[parameters('semanticSearch')]" - }, - "disableLocalAuth": { - "value": "[parameters('disableLocalAuth')]" - }, - "managedIdentityType": { - "value": "[parameters('managedIdentityType')]" - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3683977219901178221" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the existing AI Search service." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The Azure region of the search service." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resource." - } - }, - "skuName": { - "type": "string", - "defaultValue": "basic", - "metadata": { - "description": "SKU name for the search service." - } - }, - "replicaCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of replicas." - } - }, - "partitionCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of partitions." - } - }, - "hostingMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "HighDensity" - ], - "metadata": { - "description": "Hosting mode." - } - }, - "semanticSearch": { - "type": "string", - "defaultValue": "free", - "metadata": { - "description": "Semantic search tier." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Whether to disable local authentication." - } - }, - "managedIdentityType": { - "type": "string", - "defaultValue": "SystemAssigned", - "metadata": { - "description": "Managed identity type for the search service." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Public network access setting." - } - } - }, - "resources": [ - { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": { - "type": "[parameters('managedIdentityType')]" - }, - "properties": { - "replicaCount": "[parameters('replicaCount')]", - "partitionCount": "[parameters('partitionCount')]", - "hostingMode": "[parameters('hostingMode')]", - "semanticSearch": "[parameters('semanticSearch')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]" - } - } - ], - "outputs": { - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the AI Search system-assigned managed identity." - }, - "value": "[reference(resourceId('Microsoft.Search/searchServices', parameters('name')), '2025-05-01', 'full').identity.principalId]" - } - } - } + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "Enabled" + } + }, + { + "copy": { + "name": "configurationKeyValues", + "count": "[length(parameters('keyValues'))]" + }, + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", + "properties": { + "value": "[parameters('keyValues')[copyIndex()].value]" }, "dependsOn": [ - "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" ] } ], "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the AI Search service." - }, - "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "Name of the AI Search service." + "description": "The name of the App Configuration store." }, "value": "[parameters('name')]" }, "endpoint": { "type": "string", "metadata": { - "description": "Endpoint URL of the AI Search service." + "description": "The endpoint of the App Configuration store." }, - "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" }, - "identityPrincipalId": { + "resourceId": { "type": "string", "metadata": { - "description": "System-assigned identity principal ID." + "description": "The resource ID of the App Configuration store." }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', 'searchServiceUpdate'), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" } } } - } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64))]" + ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-registry.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -1875,15 +1610,13 @@ "value": "[variables('solutionSuffix')]" }, "name": { - "value": "[variables('containerAppEnvironmentName')]" + "value": "[variables('containerRegistryName')]" }, "location": { "value": "[parameters('location')]" }, - "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", - "zoneRedundant": { - "value": "[parameters('enableRedundancy')]" - }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", "tags": { "value": "[parameters('tags')]" } @@ -1895,7 +1628,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "17265155980354931238" + "templateHash": "4396841227323887436" } }, "parameters": { @@ -1907,9 +1640,9 @@ }, "name": { "type": "string", - "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", "metadata": { - "description": "Name of the Container Apps Environment." + "description": "Name of the container registry." } }, "location": { @@ -1925,44 +1658,53 @@ "description": "Resource tags." } }, - "logAnalyticsWorkspaceResourceId": { + "sku": { "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], "metadata": { - "description": "Resource ID of the Log Analytics workspace." + "description": "SKU for the container registry." } }, - "infrastructureSubnetId": { - "type": "string", - "defaultValue": "", + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Subnet resource ID for VNet integration (optional)." + "description": "Enable admin user." } }, - "zoneRedundant": { - "type": "bool", - "defaultValue": false, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Enable zone redundancy." + "description": "Public network access setting." } } }, "resources": [ { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2024-03-01", + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, "properties": { - "appLogsConfiguration": { - "destination": "log-analytics", - "logAnalyticsConfiguration": { - "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", - "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" - } - }, - "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", - "zoneRedundant": "[parameters('zoneRedundant')]" + "adminUserEnabled": "[parameters('adminUserEnabled')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "dataEndpointEnabled": false, + "networkRuleBypassOptions": "AzureServices", + "zoneRedundancy": "Disabled" } } ], @@ -1970,42 +1712,32 @@ "name": { "type": "string", "metadata": { - "description": "The name of the Container Apps Environment." + "description": "The name of the container registry." }, "value": "[parameters('name')]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container Apps Environment." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" - }, - "defaultDomain": { + "loginServer": { "type": "string", "metadata": { - "description": "The default domain of the Container Apps Environment." + "description": "The login server URL." }, - "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" }, - "staticIp": { + "resourceId": { "type": "string", "metadata": { - "description": "The static IP address of the Container Apps Environment." + "description": "The resource ID of the container registry." }, - "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" } } } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" - ] + } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.app-config.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2016,82 +1748,14 @@ "value": "[variables('solutionSuffix')]" }, "name": { - "value": "[variables('appConfigurationName')]" + "value": "[variables('containerAppEnvironmentName')]" }, "location": { "value": "[parameters('location')]" }, - "keyValues": { - "value": [ - { - "name": "APP_AZURE_OPENAI_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" - }, - { - "name": "APP_AZURE_OPENAI_MODEL", - "value": "[parameters('gptModelName')]" - }, - { - "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" - }, - { - "name": "APP_AI_PROJECT_ENDPOINT", - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName')), '2025-12-01').endpoints['AI Foundry API']]" - }, - { - "name": "APP_COSMOS_DB_ENDPOINT", - "value": "[variables('cosmosDbEndpoint')]" - }, - { - "name": "APP_COSMOS_DB_NAME", - "value": "[variables('cosmosDatabaseName')]" - }, - { - "name": "APP_COSMOS_DB_CONTAINER", - "value": "[variables('cosmosContainerName')]" - }, - { - "name": "APP_STORAGE_ACCOUNT_NAME", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" - }, - { - "name": "APP_STORAGE_BLOB_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.blobEndpoint.value]" - }, - { - "name": "APP_STORAGE_QUEUE_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" - }, - { - "name": "APP_STORAGE_CONTAINER_NAME", - "value": "[variables('storageContainerName')]" - }, - { - "name": "APP_AI_SEARCH_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" - }, - { - "name": "APP_AI_SEARCH_INDEX", - "value": "content-index" - }, - { - "name": "APP_WORKFLOW_APP_ENDPOINT", - "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" - }, - { - "name": "APP_API_ENDPOINT", - "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "AZURE_TRACING_ENABLED", - "value": "True" - } - ] + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" }, "tags": { "value": "[parameters('tags')]" @@ -2104,7 +1768,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "18286182317157861590" + "templateHash": "13592927098539789837" } }, "parameters": { @@ -2116,119 +1780,118 @@ }, "name": { "type": "string", - "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", + "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", "metadata": { - "description": "Name of the App Configuration store." + "description": "Name of the Container Apps Environment." } }, "location": { "type": "string", "metadata": { - "description": "Azure region for the resource." + "description": "Azure region for deployment." } }, "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Tags to apply to the resource." + "description": "Resource tags." } }, - "sku": { + "logAnalyticsWorkspaceResourceId": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Standard" - ], "metadata": { - "description": "SKU for the configuration store." + "description": "Resource ID of the Log Analytics workspace." } }, - "disableLocalAuth": { + "infrastructureSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for VNet integration (optional)." + } + }, + "zoneRedundant": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Disable local (key-based) authentication." + "description": "Enable zone redundancy." } }, - "keyValues": { + "workloadProfiles": { "type": "array", - "defaultValue": [], + "defaultValue": [ + { + "name": "Consumption", + "workloadProfileType": "Consumption" + } + ], "metadata": { - "description": "Key-value pairs to store in the configuration." + "description": "Workload profiles configuration (e.g., Consumption or dedicated D4 profiles)." } } }, "resources": [ { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2023-03-01", + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2024-03-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, "properties": { - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "publicNetworkAccess": "Enabled" + "appLogsConfiguration": { + "destination": "log-analytics", + "logAnalyticsConfiguration": { + "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", + "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" + } + }, + "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]" } - }, - { - "copy": { - "name": "configurationKeyValues", - "count": "[length(parameters('keyValues'))]" - }, - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2023-03-01", - "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", - "properties": { - "value": "[parameters('keyValues')[copyIndex()].value]" - }, - "dependsOn": [ - "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - ] } ], "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the App Configuration store." + "description": "The name of the Container Apps Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container Apps Environment." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" }, - "endpoint": { + "defaultDomain": { "type": "string", "metadata": { - "description": "The endpoint of the App Configuration store." + "description": "The default domain of the Container Apps Environment." }, - "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" }, - "resourceId": { + "staticIp": { "type": "string", "metadata": { - "description": "The resource ID of the App Configuration store." + "description": "The static IP address of the Container Apps Environment." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName'))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-app.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2242,7 +1905,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "disableIngress": { "value": true @@ -2251,31 +1914,21 @@ "value": [ { "name": "[variables('contentProcessorAppName')]", - "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 4, "memory": "8Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "scaleSettings": { "value": { "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", @@ -2492,17 +2145,16 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-api.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-api.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2516,7 +2168,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "ingressExternal": { "value": true @@ -2528,32 +2180,22 @@ "value": [ { "name": "[variables('contentProcessorApiName')]", - "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 2, "memory": "4Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", "probes": "[variables('apiProbes')]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "scaleSettings": { "value": { "minReplicas": 0, @@ -2770,17 +2412,16 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-web.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-web.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2794,7 +2435,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "ingressExternal": { "value": true @@ -2806,35 +2447,25 @@ "value": [ { "name": "[variables('contentProcessorWebName')]", - "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 2, "memory": "4Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "corsPolicy": { "value": { "allowedOrigins": [ - "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))]" ], "allowedMethods": [ "GET", @@ -3064,17 +2695,16 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -3088,7 +2718,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "ingressExternal": { "value": true @@ -3100,31 +2730,21 @@ "value": [ { "name": "[variables('contentProcessorWorkflowName')]", - "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 2, "memory": "4Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "scaleSettings": { "value": { "minReplicas": 0, @@ -3341,65 +2961,426 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.role-assignments.{0}', parameters('solutionName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "containerRegistryName": { + "value": "[variables('containerRegistryName')]" + }, + "storageAccountName": { + "value": "[variables('storageAccountName')]" + }, + "appConfigurationName": { + "value": "[variables('appConfigurationName')]" + }, + "aiServicesName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" + }, + "managedIdentityPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorAppPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorApiPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-api.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorWebPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-web.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorWorkflowPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12613756564324619461" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix for generating unique role assignment GUIDs." + } + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "Name of the Container Registry." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Name of the Storage Account." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Name of the App Configuration store." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Name of the AI Services account." + } + }, + "managedIdentityPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the system-assigned identity (for ACR pull)." + } + }, + "contentProcessorAppPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor App." + } + }, + "contentProcessorApiPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor API." + } + }, + "contentProcessorWebPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor Web." + } + }, + "contentProcessorWorkflowPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor Workflow." + } + } + }, + "variables": { + "roleDefinitions": { + "acrPull": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "storageBlobDataContributor": "ba92f5b4-2d11-453d-a403-e96b0029c9fe", + "storageQueueDataContributor": "974c5e8b-45b9-4653-ba55-5f855dd0fb88", + "appConfigurationDataReader": "516239f1-63e1-4d78-a4de-a74fb236a071", + "cognitiveServicesOpenAiUser": "5e0bd9bd-7b93-4f28-af87-19fc36ad61bd", + "cognitiveServicesUser": "a97b65f3-24c7-4388-baec-2e87135dc908", + "azureAiDeveloper": "64702f94-c441-49e6-a78b-ef80e0188fee" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]", + "name": "[guid(parameters('containerRegistryName'), parameters('solutionName'), 'acr-pull')]", + "properties": { + "principalId": "[parameters('managedIdentityPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').acrPull)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'app', 'blob')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'api', 'blob')]", + "properties": { + "principalId": "[parameters('contentProcessorApiPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'workflow', 'blob')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'app', 'queue')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageQueueDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'api', 'queue')]", + "properties": { + "principalId": "[parameters('contentProcessorApiPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageQueueDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'workflow', 'queue')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageQueueDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'app', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'api', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorApiPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'web', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorWebPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'workflow', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'app', 'openai-user')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesOpenAiUser)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'workflow', 'openai-user')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesOpenAiUser)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'app', 'ai-developer')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').azureAiDeveloper)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'workflow', 'ai-developer')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').azureAiDeveloper)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'app', 'cog-user')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesUser)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'workflow', 'cog-user')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesUser)]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-api.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-web.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64))]" ] } ], "outputs": { "SOLUTION_NAME": { "type": "string", + "metadata": { + "description": "The solution name." + }, "value": "[parameters('solutionName')]" }, "CONTAINER_WEB_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for Web App." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-web.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_API_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for API." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-api.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WEB_APP_FQDN": { "type": "string", - "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + "metadata": { + "description": "The FQDN of the Container App Web." + }, + "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, "CONTAINER_API_APP_FQDN": { "type": "string", - "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + "metadata": { + "description": "The FQDN of the Container App API." + }, + "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, "CONTAINER_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for APP." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for Workflow." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_APP_USER_IDENTITY_ID": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "metadata": { + "description": "The system-assigned identity resource ID used for the Container App." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "CONTAINER_APP_USER_PRINCIPAL_ID": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + "metadata": { + "description": "The system-assigned identity Principal ID used for the Container App." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" }, "CONTAINER_REGISTRY_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Azure Container Registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_REGISTRY_LOGIN_SERVER": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" + "metadata": { + "description": "The login server of the Azure Container Registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value]" }, "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "AZURE_RESOURCE_GROUP": { "type": "string", + "metadata": { + "description": "The resource group the resources were deployed into." + }, "value": "[resourceGroup().name]" } } diff --git a/infra/bicep/modules/ai/ai-foundry-connection.bicep b/infra/bicep/modules/ai/ai-foundry-connection.bicep index b0af1f6d..6649b5f7 100644 --- a/infra/bicep/modules/ai/ai-foundry-connection.bicep +++ b/infra/bicep/modules/ai/ai-foundry-connection.bicep @@ -38,6 +38,9 @@ param isDefault bool = false @description('Optional. Connection metadata object.') param metadata object = {} +@description('Optional. Whether to use workspace-managed identity for authentication.') +param useWorkspaceManagedIdentity bool = false + @secure() @description('Optional. Credentials key (for ApiKey auth type).') param credentialsKey string = '' @@ -63,6 +66,7 @@ var baseProperties = { authType: authType isSharedToAll: isSharedToAll metadata: metadata + useWorkspaceManagedIdentity: useWorkspaceManagedIdentity } var optionalDefault = isDefault ? { isDefault: true } : {} diff --git a/infra/bicep/modules/ai/ai-foundry-project.bicep b/infra/bicep/modules/ai/ai-foundry-project.bicep index 9d0dd61f..362dbbad 100644 --- a/infra/bicep/modules/ai/ai-foundry-project.bicep +++ b/infra/bicep/modules/ai/ai-foundry-project.bicep @@ -95,6 +95,12 @@ output name string = aiServices.name @description('Endpoint of the AI Services account (OpenAI Language Model Instance API).') output endpoint string = aiServices.properties.endpoints['OpenAI Language Model Instance API'] +@description('Endpoint of the AI Services account (Cognitive Services).') +output cognitiveServicesEndpoint string = aiServices.properties.endpoint + +@description('Azure OpenAI Content Understanding endpoint URL.') +output azureOpenAiCuEndpoint string = aiServices.properties.endpoints['Content Understanding'] + @description('System-assigned identity principal ID of the AI Services account.') output principalId string = aiServices.identity.principalId diff --git a/infra/bicep/modules/ai/ai-foundry.bicep b/infra/bicep/modules/ai/ai-foundry.bicep index 35cbb0f2..244e883c 100644 --- a/infra/bicep/modules/ai/ai-foundry.bicep +++ b/infra/bicep/modules/ai/ai-foundry.bicep @@ -22,7 +22,7 @@ param publicNetworkAccess string = 'Enabled' @description('Optional. Tags to apply to the resource.') param tags object = {} -resource aiServices 'Microsoft.CognitiveServices/accounts@2024-10-01' = { +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-12-01' = { name: name location: location tags: tags @@ -61,6 +61,27 @@ resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ } ] +// ============================================================================ +// AI Foundry Project (child resource of the AI Services account) +// ============================================================================ + +@description('Optional. Name of the AI Foundry project to create. If empty, no project is created.') +param projectName string = '' + +var shouldCreateProject = !empty(projectName) + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' = if (shouldCreateProject) { + parent: aiServices + name: projectName + location: location + kind: 'AIServices' + identity: { + type: 'SystemAssigned' + } + tags: tags + properties: {} +} + @description('The name of the deployed AI Services account.') output name string = aiServices.name @@ -72,3 +93,9 @@ output endpoint string = aiServices.properties.endpoint @description('The principal ID of the system-assigned managed identity.') output systemAssignedPrincipalId string = aiServices.identity.principalId + +@description('The AI Foundry project endpoint (empty if no project created).') +output projectEndpoint string = shouldCreateProject ? aiProject!.properties.endpoints['AI Foundry API'] : '' + +@description('The name of the AI Foundry project (empty if no project created).') +output projectName string = shouldCreateProject ? aiProject!.name : '' diff --git a/infra/bicep/modules/ai/ai-search-identity.bicep b/infra/bicep/modules/ai/ai-search-identity.bicep index da2309b8..ceb2dbaa 100644 --- a/infra/bicep/modules/ai/ai-search-identity.bicep +++ b/infra/bicep/modules/ai/ai-search-identity.bicep @@ -35,6 +35,12 @@ param semanticSearch string = 'free' @description('Whether to disable local authentication.') param disableLocalAuth bool = true +@description('Optional. Authentication options for the search service.') +param authOptions object = {} + +@description('Optional. Network rule set for the search service.') +param networkRuleSet object = {} + @description('Managed identity type for the search service.') param managedIdentityType string = 'SystemAssigned' @@ -58,6 +64,8 @@ resource searchServiceUpdate 'Microsoft.Search/searchServices@2025-05-01' = { semanticSearch: semanticSearch disableLocalAuth: disableLocalAuth publicNetworkAccess: publicNetworkAccess + authOptions: !empty(authOptions) ? authOptions : null + networkRuleSet: !empty(networkRuleSet) ? networkRuleSet : null } } diff --git a/infra/bicep/modules/ai/ai-search.bicep b/infra/bicep/modules/ai/ai-search.bicep index 06c31880..798a0f74 100644 --- a/infra/bicep/modules/ai/ai-search.bicep +++ b/infra/bicep/modules/ai/ai-search.bicep @@ -43,6 +43,12 @@ param semanticSearch string = 'free' @description('Whether to disable local authentication.') param disableLocalAuth bool = true +@description('Optional. Authentication options for the search service.') +param authOptions object = {} + +@description('Optional. Network rule set for the search service.') +param networkRuleSet object = {} + @description('Managed identity type for the search service.') param managedIdentityType string = 'SystemAssigned' @@ -75,6 +81,8 @@ module searchServiceUpdate 'ai-search-identity.bicep' = { hostingMode: hostingMode semanticSearch: semanticSearch disableLocalAuth: disableLocalAuth + authOptions: authOptions + networkRuleSet: networkRuleSet managedIdentityType: managedIdentityType publicNetworkAccess: publicNetworkAccess } diff --git a/infra/bicep/modules/ai/existing-project-setup.bicep b/infra/bicep/modules/ai/existing-project-setup.bicep index 37cd666d..df0acdc5 100644 --- a/infra/bicep/modules/ai/existing-project-setup.bicep +++ b/infra/bicep/modules/ai/existing-project-setup.bicep @@ -26,26 +26,35 @@ resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-12-01' ex } // ============================================================================ -// Outputs +// Outputs (aligned with ai-foundry-project.bicep) // ============================================================================ -@description('The principal ID of the AI Foundry system-assigned managed identity.') -output aiFoundryPrincipalId string = contains(aiServices, 'identity') && contains(aiServices.identity, 'principalId') ? aiServices.identity.principalId : '' +@description('Resource ID of the AI Services account.') +output resourceId string = aiServices.id -@description('The principal ID of the AI Project system-assigned managed identity.') -output aiProjectPrincipalId string = contains(aiProject, 'identity') && contains(aiProject.identity, 'principalId') ? aiProject.identity.principalId : '' +@description('Name of the AI Services account.') +output name string = aiServices.name -@description('The name of the AI Services account.') -output aiServicesAccountName string = aiServices.name +@description('Endpoint of the AI Services account (OpenAI Language Model Instance API).') +output endpoint string = aiServices.properties.endpoints['OpenAI Language Model Instance API'] -@description('The name of the AI project.') -output aiProjectName string = aiProject.name +@description('Endpoint of the AI Services account (Cognitive Services).') +output cognitiveServicesEndpoint string = aiServices.properties.endpoint -@description('The endpoint URL for the Azure OpenAI service.') -output aiFoundryEndpoint string = 'https://${name}.openai.azure.com/' +@description('Azure OpenAI Content Understanding endpoint URL.') +output azureOpenAiCuEndpoint string = aiServices.properties.endpoints['Content Understanding'] -@description('The endpoint URL for the AI Foundry project.') -output projectEndpoint string = 'https://${name}.services.ai.azure.com/api/projects/${projectName}' +@description('System-assigned identity principal ID of the AI Services account (empty if none).') +output principalId string = contains(aiServices, 'identity') && contains(aiServices.identity, 'principalId') ? aiServices.identity.principalId : '' -@description('The resource ID of the AI Services account.') -output aiFoundryResourceId string = aiServices.id +@description('Resource ID of the AI Foundry project.') +output projectResourceId string = aiProject.id + +@description('Name of the AI Foundry project.') +output projectName string = aiProject.name + +@description('AI Foundry project endpoint.') +output projectEndpoint string = aiProject.properties.endpoints['AI Foundry API'] + +@description('System-assigned identity principal ID of the project (empty if none).') +output projectIdentityPrincipalId string = contains(aiProject, 'identity') && contains(aiProject.identity, 'principalId') ? aiProject.identity.principalId : '' diff --git a/infra/bicep/modules/compute/app-service.bicep b/infra/bicep/modules/compute/app-service.bicep index 0142878e..0bacacd3 100644 --- a/infra/bicep/modules/compute/app-service.bicep +++ b/infra/bicep/modules/compute/app-service.bicep @@ -28,7 +28,30 @@ param appSettings object = {} @description('Whether to enable Always On.') param alwaysOn bool = true +@description('Optional. Health check path for the app.') +param healthCheckPath string = '' + +@description('Optional. Whether to enable WebSockets.') +param webSocketsEnabled bool = false + +@description('Optional. Command line for the application.') +param appCommandLine string = '' + @description('Kind of web app.') +@allowed([ + 'functionapp' + 'functionapp,linux' + 'functionapp,workflowapp' + 'functionapp,workflowapp,linux' + 'functionapp,linux,container' + 'functionapp,linux,container,azurecontainerapps' + 'app,linux' + 'app' + 'linux,api' + 'api' + 'app,linux,container' + 'app,container,windows' +]) param kind string = 'app,linux' @description('Subnet resource ID for VNet integration.') @@ -56,6 +79,10 @@ resource appService 'Microsoft.Web/sites@2025-05-01' = { alwaysOn: alwaysOn ftpsState: 'Disabled' linuxFxVersion: linuxFxVersion + minTlsVersion: '1.2' + healthCheckPath: !empty(healthCheckPath) ? healthCheckPath : null + webSocketsEnabled: webSocketsEnabled + appCommandLine: appCommandLine } endToEndEncryptionEnabled: true } diff --git a/infra/bicep/modules/compute/container-app-environment.bicep b/infra/bicep/modules/compute/container-app-environment.bicep index c565a158..4af7e36f 100644 --- a/infra/bicep/modules/compute/container-app-environment.bicep +++ b/infra/bicep/modules/compute/container-app-environment.bicep @@ -25,6 +25,14 @@ param infrastructureSubnetId string = '' @description('Enable zone redundancy.') param zoneRedundant bool = false +@description('Workload profiles configuration (e.g., Consumption or dedicated D4 profiles).') +param workloadProfiles array = [ + { + name: 'Consumption' + workloadProfileType: 'Consumption' + } +] + // ============================================================================ // Resource Deployment // ============================================================================ @@ -43,6 +51,7 @@ resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2024-03-01' vnetConfiguration: empty(infrastructureSubnetId) ? null : { infrastructureSubnetId: infrastructureSubnetId } + workloadProfiles: workloadProfiles zoneRedundant: zoneRedundant } } diff --git a/infra/bicep/modules/compute/container-registry.bicep b/infra/bicep/modules/compute/container-registry.bicep index 9566d218..80ce35fc 100644 --- a/infra/bicep/modules/compute/container-registry.bicep +++ b/infra/bicep/modules/compute/container-registry.bicep @@ -27,9 +27,6 @@ param adminUserEnabled bool = false @allowed(['Enabled', 'Disabled']) param publicNetworkAccess string = 'Enabled' -@description('Export policy status.') -param exportPolicyStatus string = 'enabled' - // ============================================================================ // Resource Deployment // ============================================================================ @@ -45,19 +42,6 @@ resource containerRegistry 'Microsoft.ContainerRegistry/registries@2025-04-01' = publicNetworkAccess: publicNetworkAccess dataEndpointEnabled: false networkRuleBypassOptions: 'AzureServices' - policies: { - exportPolicy: { - status: exportPolicyStatus - } - retentionPolicy: { - status: 'enabled' - days: 7 - } - trustPolicy: { - status: 'disabled' - type: 'Notary' - } - } zoneRedundancy: 'Disabled' } } diff --git a/infra/bicep/modules/compute/kubernetes.bicep b/infra/bicep/modules/compute/kubernetes.bicep index a12df945..44e29440 100644 --- a/infra/bicep/modules/compute/kubernetes.bicep +++ b/infra/bicep/modules/compute/kubernetes.bicep @@ -132,3 +132,9 @@ output resourceId string = aksCluster.id @description('FQDN of the AKS cluster.') output fqdn string = aksCluster.properties.fqdn + +@description('Object ID of the AKS kubelet system-assigned managed identity (used by pods at runtime via IMDS).') +output kubeletIdentityObjectId string = aksCluster.properties.?identityProfile.?kubeletidentity.?objectId ?? '' + +@description('Principal ID of the AKS control-plane system-assigned managed identity.') +output systemAssignedMIPrincipalId string = aksCluster.identity.?principalId ?? '' diff --git a/infra/bicep/modules/data/app-configuration.bicep b/infra/bicep/modules/data/app-configuration.bicep index 6df7aea1..ec98d977 100644 --- a/infra/bicep/modules/data/app-configuration.bicep +++ b/infra/bicep/modules/data/app-configuration.bicep @@ -21,7 +21,7 @@ param tags object = {} param sku string = 'Standard' @description('Disable local (key-based) authentication.') -param disableLocalAuth bool = true +param disableLocalAuth bool = false @description('Key-value pairs to store in the configuration.') param keyValues array = [] diff --git a/infra/bicep/modules/data/storage-account.bicep b/infra/bicep/modules/data/storage-account.bicep index ea9d5386..21b18e74 100644 --- a/infra/bicep/modules/data/storage-account.bicep +++ b/infra/bicep/modules/data/storage-account.bicep @@ -32,6 +32,9 @@ param allowBlobPublicAccess bool = false @description('Allow shared key access.') param allowSharedKeyAccess bool = true +@description('Enable hierarchical namespace (Data Lake Storage Gen2).') +param enableHierarchicalNamespace bool = false + @description('Blob containers to create.') param containers array = [ { @@ -40,6 +43,9 @@ param containers array = [ } ] +@description('Queue names to create.') +param queues array = [] + // ============================================================================ // Resource Deployment // ============================================================================ @@ -57,6 +63,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' = { allowSharedKeyAccess: allowSharedKeyAccess minimumTlsVersion: 'TLS1_2' supportsHttpsTrafficOnly: true + isHnsEnabled: enableHierarchicalNamespace encryption: { services: { blob: { @@ -85,6 +92,16 @@ resource blobContainers 'Microsoft.Storage/storageAccounts/blobServices/containe } }] +resource queueService 'Microsoft.Storage/storageAccounts/queueServices@2025-08-01' = if (!empty(queues)) { + parent: storageAccount + name: 'default' +} + +resource storageQueues 'Microsoft.Storage/storageAccounts/queueServices/queues@2025-08-01' = [for queue in queues: { + parent: queueService + name: queue +}] + // ============================================================================ // Outputs // ============================================================================ @@ -97,5 +114,8 @@ output name string = storageAccount.name @description('Primary blob endpoint.') output blobEndpoint string = storageAccount.properties.primaryEndpoints.blob +@description('Primary queue endpoint.') +output queueEndpoint string = storageAccount.properties.primaryEndpoints.queue + @description('All service endpoints.') output serviceEndpoints object = storageAccount.properties.primaryEndpoints diff --git a/infra/bicep/modules/identity/role-assignments.bicep b/infra/bicep/modules/identity/role-assignments.bicep index 00559492..edb76654 100644 --- a/infra/bicep/modules/identity/role-assignments.bicep +++ b/infra/bicep/modules/identity/role-assignments.bicep @@ -1,6 +1,7 @@ // ============================================================================ // Module: Role Assignments (centralized — all cross-service + data plane RBAC) -// Description: RG-level, cross-service, and data-plane role assignments. +// Description: Content Processing role assignments for Container Apps, +// Storage, App Configuration, and AI Services. // One place to audit "who has access to what". // ============================================================================ @@ -9,342 +10,262 @@ // ============================================================================ @description('Solution name suffix for generating unique role assignment GUIDs.') -param solutionName string = '' +param solutionName string -@description('Whether to use an existing AI project (true) or create new (false).') -param useExistingAIProject bool = false +// --- Resource Names --- -@description('Resource ID of the existing AI project (for deriving AI Services name/sub/RG).') -param existingFoundryProjectResourceId string = '' +@description('Name of the Container Registry.') +param containerRegistryName string -// --- Identity Principal IDs --- - -@description('Principal ID of the AI project identity.') -param aiProjectPrincipalId string = '' - -@description('Principal ID of the existing AI project identity (for cross-service roles).') -param existingAiProjectPrincipalId string = '' - -@description('Principal ID of the AI Search identity.') -param aiSearchPrincipalId string = '' +@description('Name of the Storage Account.') +param storageAccountName string -@description('Principal ID of the backend App Service system-assigned identity (empty if not deployed).') -param backendAppServicePrincipalId string = '' +@description('Name of the App Configuration store.') +param appConfigurationName string -@description('Principal ID of the deploying user (for user access roles).') -param deployerPrincipalId string = '' +@description('Name of the AI Services account.') +param aiServicesName string -@description('Principal type of the deploying user.') -@allowed(['User', 'ServicePrincipal']) -param deployerPrincipalType string = 'User' - -// --- Resource References --- - -@description('Resource ID of the AI Foundry account (empty if not deployed — new project path).') -param aiFoundryResourceId string = '' +// --- Identity Principal IDs --- -@description('Resource ID of the AI Search service (empty if not deployed).') -param aiSearchResourceId string = '' +@description('Principal ID of the system-assigned identity (for ACR pull).') +param managedIdentityPrincipalId string -@description('Resource ID of the Storage Account (empty if not deployed).') -param storageAccountResourceId string = '' +@description('Principal ID of the Content Processor App.') +param contentProcessorAppPrincipalId string -@description('Name of the Cosmos DB account (empty if not deployed).') -param cosmosDbAccountName string = '' +@description('Principal ID of the Content Processor API.') +param contentProcessorApiPrincipalId string -// ============================================================================ -// Derived Variables -// ============================================================================ +@description('Principal ID of the Content Processor Web.') +param contentProcessorWebPrincipalId string -var existingAIFoundryName = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[8] : '' -var existingAIFoundrySubscription = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[2] : subscription().subscriptionId -var existingAIFoundryResourceGroup = useExistingAIProject ? split(existingFoundryProjectResourceId, '/')[4] : resourceGroup().name +@description('Principal ID of the Content Processor Workflow.') +param contentProcessorWorkflowPrincipalId string // ============================================================================ // Role Definitions // ============================================================================ var roleDefinitions = { - azureAiUser: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Foundry User - cognitiveServicesUser: 'a97b65f3-24c7-4388-baec-2e87135dc908' - cognitiveServicesOpenAIUser: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' - searchIndexDataReader: '1407120a-92aa-4202-b7e9-c0e197c71c8f' - searchIndexDataContributor: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' - searchServiceContributor: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' + acrPull: '7f951dda-4ed3-4680-a7ca-43fe172d538d' storageBlobDataContributor: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' - storageBlobDataReader: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + storageQueueDataContributor: '974c5e8b-45b9-4653-ba55-5f855dd0fb88' + appConfigurationDataReader: '516239f1-63e1-4d78-a4de-a74fb236a071' + cognitiveServicesOpenAiUser: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + cognitiveServicesUser: 'a97b65f3-24c7-4388-baec-2e87135dc908' + azureAiDeveloper: '64702f94-c441-49e6-a78b-ef80e0188fee' } // ============================================================================ // Existing Resource References // ============================================================================ -resource aiFoundryAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = if (!empty(aiFoundryResourceId)) { - name: last(split(aiFoundryResourceId, '/')) -} - -resource aiSearchService 'Microsoft.Search/searchServices@2025-05-01' existing = if (!empty(aiSearchResourceId)) { - name: last(split(aiSearchResourceId, '/')) +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2025-04-01' existing = { + name: containerRegistryName } -resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' existing = if (!empty(storageAccountResourceId)) { - name: last(split(storageAccountResourceId, '/')) +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' existing = { + name: storageAccountName } -resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { - name: cosmosDbAccountName +resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = { + name: appConfigurationName } -resource cosmosContributorRoleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2025-10-15' existing = if (!empty(cosmosDbAccountName)) { - parent: cosmosAccount - name: '00000000-0000-0000-0000-000000000002' // Cosmos DB Built-in Data Contributor +resource aiServicesAccount 'Microsoft.CognitiveServices/accounts@2025-12-01' existing = { + name: aiServicesName } // ============================================================================ -// 1. AI SERVICES ROLE ASSIGNMENTS -// Cross-service roles scoped to AI Foundry account +// 1. CONTAINER REGISTRY — ACR Pull // ============================================================================ -// AI Search → Cognitive Services OpenAI User on AI Foundry (new project, same RG) -resource assignOpenAIRoleToAISearch 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiSearchPrincipalId) && !empty(aiFoundryResourceId)) { - name: guid(aiFoundryAccount.id, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) - scope: aiFoundryAccount +resource acrPullAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerRegistryName, solutionName, 'acr-pull') + scope: containerRegistry properties: { - principalId: aiSearchPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) + principalId: managedIdentityPrincipalId principalType: 'ServicePrincipal' - } -} - -// AI Search → Cognitive Services OpenAI User on existing AI Foundry (cross-scope) -module assignOpenAIToSearchExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(aiSearchPrincipalId)) { - name: 'assignOpenAIRoleToAISearchExisting' - scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) - params: { - principalId: aiSearchPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAIUser) - roleAssignmentName: guid(existingAIFoundryName, aiSearchPrincipalId, roleDefinitions.cognitiveServicesOpenAIUser) - aiFoundryName: existingAIFoundryName - } -} - -// Backend App Service → Foundry User on AI Foundry (new project, same RG) -resource backendAppAiUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(aiFoundryResourceId) && !empty(backendAppServicePrincipalId)) { - name: guid(aiFoundryAccount.id, backendAppServicePrincipalId, roleDefinitions.azureAiUser) - scope: aiFoundryAccount - properties: { - principalId: backendAppServicePrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) - principalType: 'ServicePrincipal' - } -} - -// Backend App Service → Foundry User on existing AI Foundry (cross-scope) -module backendAppAiUserExisting './cross-scope-role-assignment.bicep' = if (useExistingAIProject && !empty(backendAppServicePrincipalId)) { - name: 'assignAiUserRoleToBackendExisting' - scope: resourceGroup(existingAIFoundrySubscription, existingAIFoundryResourceGroup) - params: { - principalId: backendAppServicePrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) - roleAssignmentName: guid(existingAIFoundryName, backendAppServicePrincipalId, roleDefinitions.azureAiUser) - aiFoundryName: existingAIFoundryName + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.acrPull) } } // ============================================================================ -// 2. SEARCH SERVICE ROLE ASSIGNMENTS -// AI Project and Backend identities → AI Search +// 2. STORAGE — Blob Data Contributor // ============================================================================ -// AI Project → Search Index Data Reader on AI Search (new project) -resource projectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchIndexDataReader) - scope: aiSearchService +resource contentProcessorBlobRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, 'app', 'blob') + scope: storageAccount properties: { - principalId: aiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalId: contentProcessorAppPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) } } -// AI Project → Search Service Contributor on AI Search (new project) -resource projectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(aiSearchService.id, aiProjectPrincipalId, roleDefinitions.searchServiceContributor) - scope: aiSearchService +resource contentProcessorApiBlobRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, 'api', 'blob') + scope: storageAccount properties: { - principalId: aiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalId: contentProcessorApiPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) } } -// Existing AI Project → Search Index Data Reader on AI Search -resource existingProjectSearchReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchIndexDataReader) - scope: aiSearchService +resource contentProcessorWorkflowBlobRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, 'workflow', 'blob') + scope: storageAccount properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalId: contentProcessorWorkflowPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) } } -// Existing AI Project → Search Service Contributor on AI Search -resource existingProjectSearchContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(aiSearchResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(aiSearchService.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.searchServiceContributor) - scope: aiSearchService +// ============================================================================ +// 3. STORAGE — Queue Data Contributor +// ============================================================================ + +resource contentProcessorQueueRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, 'app', 'queue') + scope: storageAccount properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) + principalId: contentProcessorAppPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageQueueDataContributor) } } -// Backend App Service → Search Index Data Reader on AI Search -resource backendAppSearchReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiSearchResourceId) && !empty(backendAppServicePrincipalId)) { - name: guid(aiSearchService.id, backendAppServicePrincipalId, roleDefinitions.searchIndexDataReader) - scope: aiSearchService +resource contentProcessorApiQueueRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, 'api', 'queue') + scope: storageAccount properties: { - principalId: backendAppServicePrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataReader) + principalId: contentProcessorApiPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageQueueDataContributor) } } -// ============================================================================ -// 3. STORAGE ROLE ASSIGNMENTS -// AI Project, AI Search, and Existing Project identities → Storage -// ============================================================================ - -// AI Project → Storage Blob Data Contributor (new project) -resource projectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) +resource contentProcessorWorkflowQueueRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountName, 'workflow', 'queue') scope: storageAccount properties: { - principalId: aiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalId: contentProcessorWorkflowPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageQueueDataContributor) } } -// AI Project → Storage Blob Data Reader (new project) -resource projectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiProjectPrincipalId)) { - name: guid(storageAccount.id, aiProjectPrincipalId, roleDefinitions.storageBlobDataReader) - scope: storageAccount +// ============================================================================ +// 4. APP CONFIGURATION — Data Reader +// ============================================================================ + +resource contentProcessorAppConfigRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, 'app', 'appconfig') + scope: appConfiguration properties: { - principalId: aiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalId: contentProcessorAppPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.appConfigurationDataReader) } } -// Existing AI Project → Storage Blob Data Contributor -resource existingProjectStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataContributor) - scope: storageAccount +resource contentProcessorApiAppConfigRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, 'api', 'appconfig') + scope: appConfiguration properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) + principalId: contentProcessorApiPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.appConfigurationDataReader) } } -// Existing AI Project → Storage Blob Data Reader -resource existingProjectStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (useExistingAIProject && !empty(storageAccountResourceId) && !empty(existingAiProjectPrincipalId)) { - name: guid(storageAccount.id, 'existing', existingAiProjectPrincipalId, roleDefinitions.storageBlobDataReader) - scope: storageAccount +resource contentProcessorWebAppConfigRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, 'web', 'appconfig') + scope: appConfiguration properties: { - principalId: existingAiProjectPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalId: contentProcessorWebPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.appConfigurationDataReader) } } -// AI Search → Storage Blob Data Reader -resource searchStorageReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(aiSearchPrincipalId)) { - name: guid(storageAccount.id, aiSearchPrincipalId, roleDefinitions.storageBlobDataReader) - scope: storageAccount +resource contentProcessorWorkflowAppConfigRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(appConfigurationName, 'workflow', 'appconfig') + scope: appConfiguration properties: { - principalId: aiSearchPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataReader) + principalId: contentProcessorWorkflowPrincipalId principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.appConfigurationDataReader) } } // ============================================================================ -// 4. COSMOS DB ROLE ASSIGNMENTS -// Backend App Service → Cosmos DB (data-plane, uses sqlRoleAssignments) +// 5. AI SERVICES — OpenAI User, Cognitive Services User, AI Developer // ============================================================================ -resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) { - parent: cosmosAccount - name: guid(cosmosContributorRoleDefinition.id, cosmosAccount.id, backendAppServicePrincipalId) +// OpenAI User +resource contentProcessorOpenAiUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, 'app', 'openai-user') + scope: aiServicesAccount properties: { - principalId: backendAppServicePrincipalId - roleDefinitionId: cosmosContributorRoleDefinition.id - scope: cosmosAccount.id + principalId: contentProcessorAppPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAiUser) } } -// ============================================================================ -// 5. DEPLOYER (USER) ROLE ASSIGNMENTS -// Deploying user → AI Services, Search, Storage (Bicep-only) -// ============================================================================ - -// Deploying User → Cognitive Services User on AI Services -resource deployerAiServicesAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(deployerPrincipalId) && !empty(aiFoundryResourceId)) { - scope: aiFoundryAccount - name: guid(aiFoundryAccount.id, deployerPrincipalId, roleDefinitions.cognitiveServicesUser) +resource contentProcessorWorkflowOpenAiUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, 'workflow', 'openai-user') + scope: aiServicesAccount properties: { - principalId: deployerPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesUser) - principalType: deployerPrincipalType + principalId: contentProcessorWorkflowPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesOpenAiUser) } } -// Deploying User → Foundry User on AI Services -resource deployerAzureAIAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!useExistingAIProject && !empty(deployerPrincipalId) && !empty(aiFoundryResourceId)) { - scope: aiFoundryAccount - name: guid(aiFoundryAccount.id, deployerPrincipalId, roleDefinitions.azureAiUser) +// AI Developer +resource contentProcessorAiDeveloperRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, 'app', 'ai-developer') + scope: aiServicesAccount properties: { - principalId: deployerPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiUser) - principalType: deployerPrincipalType + principalId: contentProcessorAppPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiDeveloper) } } -// Deploying User → Search Index Data Contributor on AI Search -resource deployerSearchIndexContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(aiSearchResourceId)) { - scope: aiSearchService - name: guid(aiSearchService.id, deployerPrincipalId, roleDefinitions.searchIndexDataContributor) +resource contentProcessorWorkflowAiDeveloperRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, 'workflow', 'ai-developer') + scope: aiServicesAccount properties: { - principalId: deployerPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchIndexDataContributor) - principalType: deployerPrincipalType + principalId: contentProcessorWorkflowPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.azureAiDeveloper) } } -// Deploying User → Search Service Contributor on AI Search -resource deployerSearchServiceContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(aiSearchResourceId)) { - scope: aiSearchService - name: guid(aiSearchService.id, deployerPrincipalId, roleDefinitions.searchServiceContributor) +// Cognitive Services User +resource contentProcessorCogUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, 'app', 'cog-user') + scope: aiServicesAccount properties: { - principalId: deployerPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.searchServiceContributor) - principalType: deployerPrincipalType + principalId: contentProcessorAppPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesUser) } } -// Deploying User → Storage Blob Data Contributor -resource deployerStorageBlobContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId) && !empty(storageAccountResourceId)) { - scope: storageAccount - name: guid(storageAccount.id, deployerPrincipalId, roleDefinitions.storageBlobDataContributor) +resource contentProcessorWorkflowCogUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(aiServicesName, 'workflow', 'cog-user') + scope: aiServicesAccount properties: { - principalId: deployerPrincipalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor) - principalType: deployerPrincipalType + principalId: contentProcessorWorkflowPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.cognitiveServicesUser) } } - -// NOTE: Deployer roles on existing AI Foundry (cross-scope) are assigned via -// 00_build_solution.py to avoid conflicts when the deployer already has the roles. diff --git a/infra/bicep/modules/monitoring/app-insights.bicep b/infra/bicep/modules/monitoring/app-insights.bicep index f3ebe34b..21109d75 100644 --- a/infra/bicep/modules/monitoring/app-insights.bicep +++ b/infra/bicep/modules/monitoring/app-insights.bicep @@ -32,6 +32,9 @@ param disableIpMasking bool = false @description('Flow type for Application Insights.') param flowType string = 'Bluefield' +@description('Kind of Application Insights resource.') +param kind string = 'web' + // ============================================================================ // Resource // ============================================================================ @@ -40,7 +43,7 @@ resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: name location: location tags: tags - kind: 'web' + kind: kind properties: { Application_Type: applicationType Flow_Type: flowType diff --git a/infra/bicep/modules/monitoring/workbook.bicep b/infra/bicep/modules/monitoring/workbook.bicep new file mode 100644 index 00000000..1855f780 --- /dev/null +++ b/infra/bicep/modules/monitoring/workbook.bicep @@ -0,0 +1,56 @@ +// ============================================================================ +// Module: Azure Workbook +// Description: Deploys an Azure Monitor Workbook +// Resource: Microsoft.Insights/workbooks@2023-06-01 +// Docs: https://learn.microsoft.com/azure/templates/microsoft.insights/workbooks +// ============================================================================ + +@description('Solution name suffix used to derive the resource name.') +param solutionName string + +@description('Unique ID (GUID) for the workbook resource.') +param name string = guid(resourceGroup().id, solutionName, 'workbook') + +@description('Azure region for the resource.') +param location string + +@description('Tags to apply to the resource.') +param tags object = {} + +@description('Display name for the workbook.') +param displayName string = 'workbook-${solutionName}' + +@description('Serialized JSON content of the workbook definition.') +param serializedData string + +@description('Resource ID of the source (e.g., Log Analytics workspace or App Insights). Defaults to Azure Monitor.') +param sourceId string = 'azure monitor' + +@description('Gallery category for the workbook. E.g., workbook, tsg.') +param category string = 'workbook' + +// ============================================================================ +// Resource +// ============================================================================ +resource workbook 'Microsoft.Insights/workbooks@2023-06-01' = { + name: name + location: location + tags: tags + kind: 'shared' + properties: { + displayName: displayName + serializedData: serializedData + version: '1.0' + sourceId: sourceId + category: category + } +} + +// ============================================================================ +// Outputs +// ============================================================================ +@description('Name of the workbook.') +output name string = workbook.name + +@description('Resource ID of the workbook.') +output resourceId string = workbook.id diff --git a/infra/main.bicep b/infra/main.bicep index 5e816126..59c00104 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -12,16 +12,12 @@ targetScope = 'resourceGroup' // Routing Parameter // ============================================================================ -@allowed([ - 'bicep' - 'avm' - 'avm-waf' -]) +@allowed(['bicep', 'avm', 'avm-waf']) @description('Required. Deployment flavor: bicep (vanilla Docker), avm (AVM non-WAF), or avm-waf (AVM WAF-aligned).') param deploymentFlavor string = 'avm' // ============================================================================ -// Parameters — Core +// Parameters — Core (shared across all flavors) // ============================================================================ @minLength(3) @@ -29,14 +25,20 @@ param deploymentFlavor string = 'avm' @description('Optional. Name of the solution to deploy.') param solutionName string = 'cps' -@metadata({ azd: { type: 'location' } }) +@maxLength(5) +@description('Optional. A unique text suffix appended to resource names for uniqueness.') +param solutionUniqueText string = substring(uniqueString(subscription().id, resourceGroup().name, solutionName), 0, 5) + @description('Required. Azure region for the deployment.') -param location string +param location string = resourceGroup().location @metadata({ azd: { type: 'location' } }) @description('Required. Azure region for Azure AI services resources.') param azureAiServiceLocation string +@description('Optional. Secondary Azure region for redundancy scenarios.') +param secondaryLocation string = '' + // ============================================================================ // Parameters — AI Configuration // ============================================================================ @@ -55,7 +57,43 @@ param deploymentType string = 'GlobalStandard' param gptModelVersion string = '2025-11-13' @description('Optional. Capacity (TPM) for the GPT deployment.') -param gptDeploymentCapacity int = 300 +param gptDeploymentCapacity int = 50 + +@description('Optional. Azure OpenAI API version.') +param azureOpenaiAPIVersion string = '2025-01-01-preview' + +@description('Optional. Capacity for the embedding model deployment.') +param embeddingDeploymentCapacity int = 80 + +@description('Optional. Location for Azure AI Search service. Leave empty to use primary location.') +param searchServiceLocation string = '' + +// ============================================================================ +// Parameters — Compute +// ============================================================================ + +@description('Optional. Container registry endpoint. Leave empty to use the deployed ACR login server.') +param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' + +@description('Optional. Name of the Azure Container Registry. Leave empty to create a new one.') +param containerRegistryName string = '' + +@allowed(['python', 'dotnet']) +@description('Optional. Backend runtime stack.') +param backendRuntimeStack string = 'python' + +@description('Optional. Image tag for all container images.') +param imageTag string = 'latest_v2' + +// ============================================================================ +// Parameters — Feature Flags +// ============================================================================ + +@description('Optional. Enable purge protection for App Configuration.') +param enablePurgeProtection bool = false + +@description('Optional. Enable user access token forwarding.') +param useUserAccessToken bool = false // ============================================================================ // Parameters — Existing Resources @@ -67,61 +105,59 @@ param existingLogAnalyticsWorkspaceId string = '' @description('Optional. Resource ID of an existing AI Foundry project. Leave empty to create a new one.') param existingFoundryProjectResourceId string = '' +@allowed(['User', 'ServicePrincipal']) +@description('Optional. Principal type of the deploying user.') +param deployingUserPrincipalType string = 'User' + // ============================================================================ -// Parameters — Compute +// Parameters — Fabric // ============================================================================ -@description('Optional. Container registry endpoint. Leave empty to use the deployed ACR login server.') -param containerRegistryEndpoint string = '' +@description('Optional. Existing Fabric Workspace ID. Leave empty to skip.') +param fabricWorkspaceId string = '' -@description('Optional. Image tag for all container images.') -param imageTag string = 'latest_v2' +@description('Optional. Name of an existing Fabric capacity. Leave empty to skip.') +param azureFabricCapacityName string = '' + +@allowed(['F2', 'F4', 'F8', 'F16', 'F32', 'F64', 'F128', 'F256', 'F512', 'F1024', 'F2048']) +@description('Optional. SKU of the Fabric capacity.') +param fabricCapacitySku string = 'F2' + +@description('Optional. Fabric Capacity admin members.') +param fabricAdminMembers array = [] // ============================================================================ -// Parameters — Feature Flags +// Parameters — AVM-specific (ignored when deploymentFlavor = 'bicep') // ============================================================================ -@description('Optional. Enable private networking.') -param enablePrivateNetworking bool = false +@description('Optional. Tags to apply to all resources.') +param tags object = {} + +@description('Optional. Enable/Disable usage telemetry for AVM modules.') +param enableTelemetry bool = true @description('Optional. Enable monitoring resources.') param enableMonitoring bool = false -@description('Optional. Enable redundancy for supported resources.') -param enableRedundancy bool = false +@description('Optional. Enable private networking.') +param enablePrivateNetworking bool = false @description('Optional. Enable higher scale defaults for supported resources.') param enableScalability bool = false -@description('Optional. Enable AVM telemetry.') -param enableTelemetry bool = true - -@description('Optional. Enable purge protection for App Configuration.') -param enablePurgeProtection bool = false - -// ============================================================================ -// Parameters — WAF (AVM-WAF only) -// ============================================================================ +@description('Optional. Enable redundancy for supported resources.') +param enableRedundancy bool = false +@secure() @description('Optional. VM admin username for WAF jumpbox (avm-waf only).') -param vmAdminUsername string = '' +param vmAdminUsername string? @secure() @description('Optional. VM admin password for WAF jumpbox (avm-waf only).') -param vmAdminPassword string = '' +param vmAdminPassword string? @description('Optional. VM size for WAF jumpbox (avm-waf only).') -param vmSize string = '' - -// ============================================================================ -// Parameters — Tags -// ============================================================================ - -@description('Optional. Tags to be applied to resources.') -param tags object = { - app: 'Content Processing Solution Accelerator' - location: resourceGroup().location -} +param vmSize string = 'Standard_D2s_v5' // ============================================================================ // Derived Variables @@ -137,13 +173,14 @@ var effectiveEnableRedundancy = useWafDefaults ? true : enableRedundancy var effectiveEnableScalability = useWafDefaults ? true : enableScalability // ============================================================================ -// Module: AVM Deployment +// Module calls // ============================================================================ module avmDeployment './avm/main.bicep' = if (isAvm) { name: take('module.avm.${solutionName}', 64) params: { solutionName: solutionName + solutionUniqueText: solutionUniqueText location: location azureAiServiceLocation: azureAiServiceLocation gptModelName: gptModelName @@ -167,17 +204,19 @@ module avmDeployment './avm/main.bicep' = if (isAvm) { } } -// ============================================================================ -// Module: Vanilla Bicep Deployment -// ============================================================================ - module bicepDeployment './bicep/main.bicep' = if (isBicep) { name: take('module.bicep.${solutionName}', 64) params: { solutionName: solutionName + solutionUniqueText: solutionUniqueText location: location azureAiServiceLocation: azureAiServiceLocation gptModelName: gptModelName + deploymentType: deploymentType + gptModelVersion: gptModelVersion + gptDeploymentCapacity: gptDeploymentCapacity + existingLogAnalyticsWorkspaceId: existingLogAnalyticsWorkspaceId + existingFoundryProjectResourceId: existingFoundryProjectResourceId containerRegistryEndpoint: containerRegistryEndpoint imageTag: imageTag enablePrivateNetworking: effectiveEnablePrivateNetworking @@ -191,19 +230,44 @@ module bicepDeployment './bicep/main.bicep' = if (isBicep) { } // ============================================================================ -// Outputs — Coalesced from whichever flavor was deployed +// Outputs // ============================================================================ +@description('Solution name output from the selected deployment flavor.') output SOLUTION_NAME string = isAvm ? avmDeployment!.outputs.SOLUTION_NAME : bicepDeployment!.outputs.SOLUTION_NAME + +@description('Container web app name from the selected deployment flavor.') output CONTAINER_WEB_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_WEB_APP_NAME : bicepDeployment!.outputs.CONTAINER_WEB_APP_NAME + +@description('Container API app name from the selected deployment flavor.') output CONTAINER_API_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_API_APP_NAME : bicepDeployment!.outputs.CONTAINER_API_APP_NAME + +@description('Container web app FQDN from the selected deployment flavor.') output CONTAINER_WEB_APP_FQDN string = isAvm ? avmDeployment!.outputs.CONTAINER_WEB_APP_FQDN : bicepDeployment!.outputs.CONTAINER_WEB_APP_FQDN + +@description('Container API app FQDN from the selected deployment flavor.') output CONTAINER_API_APP_FQDN string = isAvm ? avmDeployment!.outputs.CONTAINER_API_APP_FQDN : bicepDeployment!.outputs.CONTAINER_API_APP_FQDN + +@description('Container app name from the selected deployment flavor.') output CONTAINER_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_NAME : bicepDeployment!.outputs.CONTAINER_APP_NAME + +@description('Container workflow app name from the selected deployment flavor.') output CONTAINER_WORKFLOW_APP_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_WORKFLOW_APP_NAME : bicepDeployment!.outputs.CONTAINER_WORKFLOW_APP_NAME + +@description('Container app user-assigned identity resource ID from the selected deployment flavor.') output CONTAINER_APP_USER_IDENTITY_ID string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_USER_IDENTITY_ID : bicepDeployment!.outputs.CONTAINER_APP_USER_IDENTITY_ID + +@description('Container app user-assigned identity principal ID from the selected deployment flavor.') output CONTAINER_APP_USER_PRINCIPAL_ID string = isAvm ? avmDeployment!.outputs.CONTAINER_APP_USER_PRINCIPAL_ID : bicepDeployment!.outputs.CONTAINER_APP_USER_PRINCIPAL_ID + +@description('Container registry name from the selected deployment flavor.') output CONTAINER_REGISTRY_NAME string = isAvm ? avmDeployment!.outputs.CONTAINER_REGISTRY_NAME : bicepDeployment!.outputs.CONTAINER_REGISTRY_NAME + +@description('Container registry login server from the selected deployment flavor.') output CONTAINER_REGISTRY_LOGIN_SERVER string = isAvm ? avmDeployment!.outputs.CONTAINER_REGISTRY_LOGIN_SERVER : bicepDeployment!.outputs.CONTAINER_REGISTRY_LOGIN_SERVER + +@description('Content Understanding account name from the selected deployment flavor.') output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = isAvm ? avmDeployment!.outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME : bicepDeployment!.outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME + +@description('Azure resource group output from the selected deployment flavor.') output AZURE_RESOURCE_GROUP string = isAvm ? avmDeployment!.outputs.AZURE_RESOURCE_GROUP : bicepDeployment!.outputs.AZURE_RESOURCE_GROUP diff --git a/infra/main.json b/infra/main.json index fbefa771..b22b5122 100644 --- a/infra/main.json +++ b/infra/main.json @@ -1,11 +1,12 @@ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "15979971030931723082" + "templateHash": "10022031835417533232" } }, "parameters": { @@ -30,12 +31,18 @@ "description": "Optional. Name of the solution to deploy." } }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text suffix appended to resource names for uniqueness." + } + }, "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "azd": { - "type": "location" - }, "description": "Required. Azure region for the deployment." } }, @@ -48,6 +55,13 @@ "description": "Required. Azure region for Azure AI services resources." } }, + "secondaryLocation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Secondary Azure region for redundancy scenarios." + } + }, "gptModelName": { "type": "string", "defaultValue": "gpt-5.1", @@ -80,27 +94,52 @@ "description": "Optional. Capacity (TPM) for the GPT deployment." } }, - "existingLogAnalyticsWorkspaceId": { + "azureOpenaiAPIVersion": { "type": "string", - "defaultValue": "", + "defaultValue": "2025-01-01-preview", "metadata": { - "description": "Optional. Resource ID of an existing Log Analytics workspace. Leave empty to create a new one." + "description": "Optional. Azure OpenAI API version." } }, - "existingFoundryProjectResourceId": { + "embeddingDeploymentCapacity": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Capacity for the embedding model deployment." + } + }, + "searchServiceLocation": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. Resource ID of an existing AI Foundry project. Leave empty to create a new one." + "description": "Optional. Location for Azure AI Search service. Leave empty to use primary location." } }, "containerRegistryEndpoint": { "type": "string", - "defaultValue": "", + "defaultValue": "cpscontainerreg.azurecr.io", "metadata": { "description": "Optional. Container registry endpoint. Leave empty to use the deployed ACR login server." } }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the Azure Container Registry. Leave empty to create a new one." + } + }, + "backendRuntimeStack": { + "type": "string", + "defaultValue": "python", + "allowedValues": [ + "python", + "dotnet" + ], + "metadata": { + "description": "Optional. Backend runtime stack." + } + }, "imageTag": { "type": "string", "defaultValue": "latest_v2", @@ -108,78 +147,148 @@ "description": "Optional. Image tag for all container images." } }, - "enablePrivateNetworking": { + "enablePurgeProtection": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable private networking." + "description": "Optional. Enable purge protection for App Configuration." } }, - "enableMonitoring": { + "useUserAccessToken": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable monitoring resources." + "description": "Optional. Enable user access token forwarding." } }, - "enableRedundancy": { + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an existing Log Analytics workspace. Leave empty to create a new one." + } + }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an existing AI Foundry project. Leave empty to create a new one." + } + }, + "deployingUserPrincipalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "User", + "ServicePrincipal" + ], + "metadata": { + "description": "Optional. Principal type of the deploying user." + } + }, + "fabricWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Existing Fabric Workspace ID. Leave empty to skip." + } + }, + "azureFabricCapacityName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of an existing Fabric capacity. Leave empty to skip." + } + }, + "fabricCapacitySku": { + "type": "string", + "defaultValue": "F2", + "allowedValues": [ + "F2", + "F4", + "F8", + "F16", + "F32", + "F64", + "F128", + "F256", + "F512", + "F1024", + "F2048" + ], + "metadata": { + "description": "Optional. SKU of the Fabric capacity." + } + }, + "fabricAdminMembers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Fabric Capacity admin members." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to apply to all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for AVM modules." + } + }, + "enableMonitoring": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable redundancy for supported resources." + "description": "Optional. Enable monitoring resources." } }, - "enableScalability": { + "enablePrivateNetworking": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable higher scale defaults for supported resources." + "description": "Optional. Enable private networking." } }, - "enableTelemetry": { + "enableScalability": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable AVM telemetry." + "description": "Optional. Enable higher scale defaults for supported resources." } }, - "enablePurgeProtection": { + "enableRedundancy": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Enable purge protection for App Configuration." + "description": "Optional. Enable redundancy for supported resources." } }, "vmAdminUsername": { - "type": "string", - "defaultValue": "", + "type": "securestring", + "nullable": true, "metadata": { "description": "Optional. VM admin username for WAF jumpbox (avm-waf only)." } }, "vmAdminPassword": { "type": "securestring", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. VM admin password for WAF jumpbox (avm-waf only)." } }, "vmSize": { "type": "string", - "defaultValue": "", + "defaultValue": "Standard_D2s_v5", "metadata": { "description": "Optional. VM size for WAF jumpbox (avm-waf only)." } - }, - "tags": { - "type": "object", - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - }, - "metadata": { - "description": "Optional. Tags to be applied to resources." - } } }, "variables": { @@ -191,8 +300,8 @@ "effectiveEnableRedundancy": "[if(variables('useWafDefaults'), true(), parameters('enableRedundancy'))]", "effectiveEnableScalability": "[if(variables('useWafDefaults'), true(), parameters('enableScalability'))]" }, - "resources": [ - { + "resources": { + "avmDeployment": { "condition": "[variables('isAvm')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", @@ -206,6 +315,9 @@ "solutionName": { "value": "[parameters('solutionName')]" }, + "solutionUniqueText": { + "value": "[parameters('solutionUniqueText')]" + }, "location": { "value": "[parameters('location')]" }, @@ -269,16 +381,13 @@ }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "12171467271723171429" - }, - "name": "Content Processing Solution Accelerator", - "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." + "templateHash": "7252398242832354268" + } }, "parameters": { "solutionName": { @@ -309,6 +418,97 @@ "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" + }, + "description": "Optional. Tags to be applied to the resources." + }, + "defaultValue": { + "app": "Content Processing Solution Accelerator", + "location": "[resourceGroup().location]" + } + }, + "createdBy": { + "type": "string", + "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", + "metadata": { + "description": "Optional. Tag, Created by user name." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable WAF for the deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." + } + }, + "enableRedundancy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enableScalability": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable purge protection. Defaults to false." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminUsername": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, + "vmAdminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." + } + }, "azureAiServiceLocation": { "type": "string", "allowedValues": [ @@ -387,61 +587,6 @@ "description": "Optional. The image tag for the container images." } }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable WAF for the deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableMonitoring": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false." - } - }, - "enableRedundancy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." - } - }, - "enableScalability": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable purge protection. Defaults to false." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Resources/resourceGroups@2025-04-01#properties/tags" - }, - "description": "Optional. Tags to be applied to the resources." - }, - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - } - }, "existingLogAnalyticsWorkspaceId": { "type": "string", "defaultValue": "", @@ -455,42 +600,6 @@ "metadata": { "description": "Use this parameter to use an existing AI project resource ID" } - }, - "vmSize": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." - } - }, - "vmAdminUsername": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Admin username for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." - } - }, - "vmAdminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Admin password for the Jumpbox Virtual Machine. Set to custom value if enablePrivateNetworking is true." - } - }, - "solutionUniqueText": { - "type": "string", - "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", - "maxLength": 5, - "metadata": { - "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name." - } - }, - "createdBy": { - "type": "string", - "defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]", - "metadata": { - "description": "Optional. Tag, Created by user name." - } } }, "variables": { @@ -537,8 +646,16 @@ "containerRegistry": 8 } }, - "resources": { - "avmTelemetry": { + "resources": [ + { + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", + "properties": { + "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" + } + }, + { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", @@ -558,19 +675,11 @@ } } }, - "resourceGroupTags": { - "type": "Microsoft.Resources/tags", - "apiVersion": "2025-04-01", - "name": "default", - "properties": { - "tags": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags'), createObject('TemplateName', 'Content Processing', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy'), 'DeploymentName', deployment().name)))]" - } - }, - "virtualNetwork": { - "condition": "[parameters('enablePrivateNetworking')]", + { + "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -580,10 +689,8 @@ "solutionName": { "value": "[variables('solutionSuffix')]" }, - "addressPrefixes": { - "value": [ - "10.0.0.0/8" - ] + "name": { + "value": "[variables('logAnalyticsWorkspaceResourceName')]" }, "location": { "value": "[parameters('location')]" @@ -591,12 +698,14 @@ "tags": { "value": "[parameters('tags')]" }, - "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "resourceSuffix": { - "value": "[variables('solutionSuffix')]" - }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" + }, + "enableReplication": { + "value": "[parameters('enableRedundancy')]" + }, + "replicationLocation": { + "value": "[variables('replicaLocation')]" } }, "template": { @@ -607,164 +716,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "10323079586505814920" - } - }, - "definitions": { - "subnetOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the subnet." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the subnet." - } - }, - "nsgName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The name of the associated NSG, if any." - } - }, - "nsgResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The resource ID of the associated NSG, if any." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Subnet output type" - } - }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the subnet." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. Address prefixes for the subnet." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Delegation for the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Private endpoint network policies." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Private link service network policies." - } - }, - "networkSecurityGroup": { - "$ref": "#/definitions/networkSecurityGroupType", - "nullable": true, - "metadata": { - "description": "Optional. NSG configuration for the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Route table resource ID." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. Service endpoint policies." - } - }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Service endpoints to enable." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Disable default outbound connectivity." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Subnet configuration type" - } - }, - "networkSecurityGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NSG." - } - }, - "securityRules": { - "type": "array", - "items": { - "type": "object" - }, - "metadata": { - "description": "Required. Security rules for the NSG." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "NSG configuration type" - } + "templateHash": "9919485194443011422" } }, "parameters": { @@ -774,191 +726,38 @@ "description": "Solution name suffix used to derive the resource name." } }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "[format('log-{0}', parameters('solutionName'))]", "metadata": { - "description": "Azure region for the resource." + "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." } }, - "addressPrefixes": { - "type": "array", + "location": { + "type": "string", "metadata": { - "description": "Address prefixes for the virtual network." - } - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "defaultValue": [ - { - "name": "backend", - "addressPrefixes": [ - "10.0.0.0/27" - ], - "networkSecurityGroup": { - "name": "nsg-backend", - "securityRules": [ - { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "destinationAddressPrefix": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "direction": "Outbound", - "priority": 200, - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*" - } - } - ] - } - }, - { - "name": "webserverfarm", - "addressPrefixes": [ - "10.0.4.0/27" - ], - "delegation": "Microsoft.Web/serverfarms", - "privateEndpointNetworkPolicies": "Enabled", - "privateLinkServiceNetworkPolicies": "Enabled", - "networkSecurityGroup": { - "name": "nsg-webserverfarm", - "securityRules": [ - { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "destinationAddressPrefix": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "direction": "Outbound", - "priority": 200, - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*" - } - } - ] - } - }, - { - "name": "administration", - "addressPrefixes": [ - "10.0.0.32/27" - ], - "networkSecurityGroup": { - "name": "nsg-administration", - "securityRules": [ - { - "name": "deny-hop-outbound", - "properties": { - "access": "Deny", - "destinationAddressPrefix": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "direction": "Outbound", - "priority": 200, - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*" - } - } - ] - } - }, - { - "name": "AzureBastionSubnet", - "addressPrefixes": [ - "10.0.0.64/26" - ], - "networkSecurityGroup": { - "name": "nsg-bastion", - "securityRules": [ - { - "name": "AllowGatewayManager", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2702, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "GatewayManager", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowHttpsInBound", - "properties": { - "access": "Allow", - "direction": "Inbound", - "priority": 2703, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "Internet", - "destinationAddressPrefix": "*" - } - }, - { - "name": "AllowSshRdpOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 100, - "protocol": "*", - "sourcePortRange": "*", - "destinationPortRanges": [ - "22", - "3389" - ], - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AllowAzureCloudOutbound", - "properties": { - "access": "Allow", - "direction": "Outbound", - "priority": 110, - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "443", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "AzureCloud" - } - } - ] - } - } - ], - "metadata": { - "description": "Subnet configurations." + "description": "Azure region for the resource." } }, "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Tags to apply to the resources." + "description": "Tags to apply to the resource." } }, - "logAnalyticsWorkspaceId": { + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Retention period in days. WAF recommends 365." + } + }, + "skuName": { "type": "string", + "defaultValue": "PerGB2018", "metadata": { - "description": "Resource ID of the Log Analytics Workspace for diagnostics." + "description": "SKU name for the workspace." } }, "enableTelemetry": { @@ -968,28 +767,54 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "resourceSuffix": { + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access for ingestion." + } + }, + "publicNetworkAccessForQuery": { "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Suffix for resource naming." + "description": "Public network access for query." + } + }, + "enableReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable workspace replication for redundancy." + } + }, + "replicationLocation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Replication location (paired region)." + } + }, + "dailyQuotaGb": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Data sources for VM monitoring (Windows events, perf counters)." } } }, - "variables": { - "name": "[format('vnet-{0}', parameters('solutionName'))]" - }, "resources": { - "nsgs": { - "copy": { - "name": "nsgs", - "count": "[length(parameters('subnets'))]", - "mode": "serial", - "batchSize": 1 - }, - "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", + "workspace": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", + "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -997,20 +822,44 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" + "value": "[parameters('name')]" }, "location": { "value": "[parameters('location')]" }, - "securityRules": { - "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" - }, "tags": { "value": "[parameters('tags')]" }, + "dataRetention": { + "value": "[parameters('retentionInDays')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" - } + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "diagnosticSettings": { + "value": [ + { + "useThisWorkspace": true + } + ] + }, + "publicNetworkAccessForIngestion": { + "value": "[parameters('publicNetworkAccessForIngestion')]" + }, + "publicNetworkAccessForQuery": { + "value": "[parameters('publicNetworkAccessForQuery')]" + }, + "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", + "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", + "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1019,174 +868,14 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7311263652424030280" + "version": "0.39.26.7824", + "templateHash": "14099489006827800075" }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace." }, "definitions": { - "securityRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "metadata": { - "description": "Required. The properties of the security rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a security rule." - } - }, - "diagnosticSettingLogsOnlyType": { + "diagnosticSettingType": { "type": "object", "properties": { "name": { @@ -1229,6 +918,31 @@ "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ @@ -1240,6 +954,13 @@ "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, "workspaceResourceId": { "type": "string", "nullable": true, @@ -1275,848 +996,553 @@ "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } }, - "lockType": { + "gallerySolutionType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." } }, - "notes": { - "type": "string", - "nullable": true, + "plan": { + "$ref": "#/definitions/solutionPlanType", "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "Properties of the gallery solutions to be created in the log analytics workspace." } }, - "roleAssignmentType": { + "storageInsightsConfigType": { "type": "object", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { + "storageAccountResourceId": { "type": "string", "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Required. Resource ID of the storage account to be linked." } }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], + "containers": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The names of the blob containers that the workspace should read." } }, - "description": { - "type": "string", + "tables": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. List of tables to be read by the workspace." } - }, - "condition": { + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the storage insights configuration." + } + }, + "linkedServiceType": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." } }, - "conditionVersion": { + "resourceId": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." } }, - "delegatedManagedIdentityResourceId": { + "writeAccessResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "__bicep_export!": true, + "description": "Properties of the linked service." } }, - "tags": { + "linkedStorageAccountType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" - }, - "description": "Optional. Tags of the NSG resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", - "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" - } - } + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." + } }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "addressPrefixes": { - "value": "[parameters('addressPrefixes')]" - }, - "subnets": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('subnets'))]", - "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" - } - ] - }, - "diagnosticSettings": { - "value": [ - { - "name": "vnetDiagnostics", - "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", - "logCategoriesAndGroups": [ - { - "categoryGroup": "allLogs", - "enabled": true - } - ], - "metricCategories": [ - { - "category": "AllMetrics", - "enabled": true - } - ] + "__bicep_export!": true, + "description": "Properties of the linked storage account." } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "11272001757446231867" }, - "name": "Virtual Networks", - "description": "This module deploys a Virtual Network (vNet)." - }, - "definitions": { - "peeringType": { + "savedSearchType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + "description": "Required. Name of the saved search." } }, - "remoteVirtualNetworkResourceId": { + "etag": { "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." } }, - "allowGatewayTransit": { - "type": "bool", - "nullable": true, + "category": { + "type": "string", "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + "description": "Required. The category of the saved search. This helps the user to find a saved search faster." } }, - "allowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, + "displayName": { + "type": "string", "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + "description": "Required. Display name for the search." } }, - "doNotVerifyRemoteGateways": { - "type": "bool", + "functionAlias": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + "description": "Optional. The function alias if query serves as a function." } }, - "useRemoteGateways": { - "type": "bool", + "functionParameters": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." } }, - "remotePeeringEnabled": { - "type": "bool", - "nullable": true, + "query": { + "type": "string", "metadata": { - "description": "Optional. Deploy the outbound and the inbound peering." + "description": "Required. The query expression for the saved search." } }, - "remotePeeringName": { - "type": "string", + "tags": { + "type": "array", "nullable": true, "metadata": { - "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + "description": "Optional. The tags attached to the saved search." } }, - "remotePeeringAllowForwardedTraffic": { - "type": "bool", + "version": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + "description": "Optional. The version number of the query language. The current version is 2 and is the default." } - }, - "remotePeeringAllowGatewayTransit": { - "type": "bool", - "nullable": true, + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the saved search." + } + }, + "dataExportType": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + "description": "Required. Name of the data export." } }, - "remotePeeringAllowVirtualNetworkAccess": { - "type": "bool", + "destination": { + "$ref": "#/definitions/destinationType", "nullable": true, "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + "description": "Optional. The destination of the data export." } }, - "remotePeeringDoNotVerifyRemoteGateways": { + "enable": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + "description": "Optional. Enable or disable the data export." } }, - "remotePeeringUseRemoteGateways": { - "type": "bool", - "nullable": true, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + "description": "Required. The list of table names to export." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "Properties of the data export." } }, - "subnetType": { + "dataSourceType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The Name of the subnet resource." + "description": "Required. Name of the data source." } }, - "addressPrefix": { + "kind": { "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + "description": "Required. The kind of data source." } }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, + "linkedResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + "description": "Optional. The resource id of the resource that will be linked to the workspace." } }, - "ipamPoolPrefixAllocations": { - "type": "array", - "prefixItems": [ - { - "type": "object", - "properties": { - "pool": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the IPAM pool." - } - } - }, - "metadata": { - "description": "Required. The Resource ID of the IPAM pool." - } - }, - "numberOfIpAddresses": { - "type": "string", - "metadata": { - "description": "Required. Number of IP addresses allocated from the pool." - } - } - } - } - ], - "items": false, + "eventLogName": { + "type": "string", "nullable": true, "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." + "description": "Optional. The name of the event log to configure when kind is WindowsEvent." } }, - "applicationGatewayIPConfigurations": { + "eventTypes": { "type": "array", - "items": { - "type": "object" - }, "nullable": true, "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "description": "Optional. The event types to configure when kind is WindowsEvent." } }, - "delegation": { + "objectName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The delegation to enable on the subnet." + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." } }, - "natGatewayResourceId": { + "instanceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." } }, - "networkSecurityGroupResourceId": { + "intervalSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." } }, - "privateEndpointNetworkPolicies": { + "state": { "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], "nullable": true, "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." } }, - "privateLinkServiceNetworkPolicies": { + "syslogName": { "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], "nullable": true, "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." + "description": "Optional. System log to configure when kind is LinuxSyslog." } }, - "roleAssignments": { + "syslogSeverities": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Severities to configure when kind is LinuxSyslog." } }, - "routeTableResourceId": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data source." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "plan": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." + "description": "Optional. The plan for the table." } }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", "nullable": true, "metadata": { - "description": "Optional. An array of service endpoint policies." + "description": "Optional. The restored logs for the table." } }, - "serviceEndpoints": { + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. The schema for the table." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. The search results for the table." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." + } + }, + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." + "description": "Optional. The role assignments for the table." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the custom table." + } + }, + "workspaceFeaturesType": { + "type": "object", + "properties": { + "disableLocalAuth": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable Non-EntraID based Auth. Default is true." } }, - "defaultOutboundAccess": { + "enableDataExport": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + "description": "Optional. Flag that indicate if data should be exported." } }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], + "enableLogAccessUsingOnlyResourcePermissions": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + "description": "Optional. Enable log access using only resource permissions. Default is false." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that describes if we want to remove the data after 30 days." } } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "Features of the workspace." } }, - "diagnosticSettingFullType": { + "workspaceReplicationType": { "type": "object", "properties": { - "name": { - "type": "string", + "enabled": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." } }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, + "location": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Replication properties of the workspace." + } + }, + "_1.columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Required. The column name." } }, - "logAnalyticsDestinationType": { + "type": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" ], - "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + "description": "Required. The column type." } }, - "workspaceResourceId": { + "dataTypeHint": { "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The column data type logical hint." } }, - "storageAccountResourceId": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The column description." } }, - "eventHubAuthorizationRuleResourceId": { + "displayName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Optional. Column display name." } - }, - "eventHubName": { + } + }, + "metadata": { + "description": "The parameters of the table column.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "destinationType": { + "type": "object", + "properties": { + "resourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Required. The destination resource ID." } }, - "marketplacePartnerResourceId": { - "type": "string", + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. The destination metadata." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "The data export destination properties.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + "sourceTemplate": "data-export/main.bicep" } } }, @@ -2153,7 +1579,67 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the restore operation that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" } } }, @@ -2228,118 +1714,338 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "parameters": { - "name": { - "type": "string", + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, "metadata": { - "description": "Required. The name of the Virtual Network (vNet)." + "description": "The table schema.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, "metadata": { - "description": "Optional. Location for all resources." + "description": "The parameters of the search job that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } } }, - "addressPrefixes": { - "type": "array", + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." } }, - "ipamPoolNumberOfIpAddresses": { + "location": { "type": "string", - "nullable": true, + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." + "description": "Optional. Location for all resources." } }, - "virtualNetworkBgpCommunity": { + "skuName": { "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/storageInsightsConfigType" + }, "nullable": true, "metadata": { - "description": "Optional. The BGP community associated with the virtual network." + "description": "Optional. List of storage accounts to be read by the workspace." } }, - "subnets": { + "linkedServices": { "type": "array", "items": { - "$ref": "#/definitions/subnetType" + "$ref": "#/definitions/linkedServiceType" }, "nullable": true, "metadata": { - "description": "Optional. An Array of subnets to deploy to the Virtual Network." + "description": "Optional. List of services to be linked." } }, - "dnsServers": { + "linkedStorageAccounts": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/linkedStorageAccountType" }, "nullable": true, "metadata": { - "description": "Optional. DNS Servers associated to the Virtual Network." + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." } }, - "ddosProtectionPlanResourceId": { - "type": "string", + "savedSearches": { + "type": "array", + "items": { + "$ref": "#/definitions/savedSearchType" + }, "nullable": true, "metadata": { - "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + "description": "Optional. Kusto Query Language searches to save." } }, - "peerings": { + "dataExports": { "type": "array", "items": { - "$ref": "#/definitions/peeringType" + "$ref": "#/definitions/dataExportType" }, "nullable": true, "metadata": { - "description": "Optional. Virtual Network Peering configurations." + "description": "Optional. LAW data export instances to be deployed." } }, - "vnetEncryption": { + "dataSources": { + "type": "array", + "items": { + "$ref": "#/definitions/dataSourceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." + } + }, + "onboardWorkspaceToSentinel": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." } }, - "vnetEncryptionEnforcement": { + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { "type": "string", - "defaultValue": "AllowUnencrypted", + "defaultValue": "-1", + "metadata": { + "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." + } + }, + "defaultDataCollectionRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", "allowedValues": [ - "AllowUnencrypted", - "DropUnencrypted" + "Enabled", + "Disabled", + "SecuredByPerimeter" ], "metadata": { - "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + "description": "Optional. The network access type for accessing Log Analytics ingestion." } }, - "flowTimeoutInMinutes": { - "type": "int", - "defaultValue": 0, - "maxValue": 30, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], "metadata": { - "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "features": { + "$ref": "#/definitions/workspaceFeaturesType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace features." + } + }, + "replication": { + "$ref": "#/definitions/workspaceReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace replication properties." } }, "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/diagnosticSettingType" }, "nullable": true, "metadata": { "description": "Optional. The diagnostic settings of the service." } }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, "lock": { "$ref": "#/definitions/lockType", "nullable": true, @@ -2359,10 +2065,13 @@ }, "tags": { "type": "object", - "nullable": true, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" + }, "description": "Optional. Tags of the resource." - } + }, + "nullable": true }, "enableTelemetry": { "type": "bool", @@ -2370,24 +2079,6 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "enableVmProtection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." - } - }, - "enablePrivateEndpointVNetPolicies": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Basic", - "Disabled" - ], - "metadata": { - "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." - } } }, "variables": { @@ -2399,12 +2090,19 @@ } ], "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -2413,7 +2111,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2429,46 +2127,44 @@ } } }, - "virtualNetwork": { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-05-01", + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", - "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", - "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", - "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", - "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", - "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", - "enableVmProtection": "[parameters('enableVmProtection')]", - "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" - } - }, - "virtualNetwork_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", + "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", + "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", + "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]", + "replication": "[parameters('replication')]", + "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" }, - "dependsOn": [ - "virtualNetwork" - ] + "identity": "[variables('identity')]" }, - "virtualNetwork_diagnosticSettings": { + "logAnalyticsWorkspace_diagnosticSettings": { "copy": { - "name": "virtualNetwork_diagnosticSettings", + "name": "logAnalyticsWorkspace_diagnosticSettings", "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -2492,25 +2188,50 @@ } ], "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "virtualNetwork" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_roleAssignments": { + "logAnalyticsWorkspace_sentinelOnboarding": { + "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", + "type": "Microsoft.SecurityInsights/onboardingStates", + "apiVersion": "2025-09-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "default", + "properties": {}, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { "copy": { - "name": "virtualNetwork_roleAssignments", + "name": "logAnalyticsWorkspace_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -2521,78 +2242,34 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "virtualNetwork" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_subnets": { + "logAnalyticsWorkspace_storageInsightConfigs": { "copy": { - "name": "virtualNetwork_subnets", - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "mode": "serial", - "batchSize": 1 + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "virtualNetworkName": { + "logAnalyticsWorkspaceName": { "value": "[parameters('name')]" }, - "name": { - "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" - }, - "addressPrefix": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" - }, - "addressPrefixes": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" - }, - "ipamPoolPrefixAllocations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" - }, - "applicationGatewayIPConfigurations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" - }, - "delegation": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" - }, - "natGatewayResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" - }, - "networkSecurityGroupResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" - }, - "privateEndpointNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" - }, - "privateLinkServiceNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "routeTableResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" - }, - "serviceEndpointPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" - }, - "serviceEndpoints": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" - }, - "defaultOutboundAccess": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + "containers": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" }, - "sharingScope": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + "tables": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "storageAccountResourceId": { + "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" } }, "template": { @@ -2602,1733 +2279,1825 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13992200806189615656" + "version": "0.39.26.7824", + "templateHash": "140290971998938797" }, - "name": "Virtual Network Subnets", - "description": "This module deploys a Virtual Network Subnet." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - } + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." }, "parameters": { - "name": { + "logAnalyticsWorkspaceName": { "type": "string", "metadata": { - "description": "Required. The Name of the subnet resource." + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "virtualNetworkName": { + "name": { "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", "metadata": { - "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + "description": "Optional. The name of the storage insights config." } }, - "addressPrefix": { + "storageAccountResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + "description": "Required. The Azure Resource Manager ID of the storage account resource." } }, - "ipamPoolPrefixAllocations": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpoints": { + "containers": { "type": "array", "items": { "type": "string" }, - "defaultValue": [], - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "metadata": { - "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled" - ], "metadata": { - "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + "description": "Optional. The names of the blob containers that the workspace should read." } }, - "addressPrefixes": { + "tables": { "type": "array", "items": { "type": "string" }, "nullable": true, "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, - "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "description": "Optional. The names of the Azure tables that the workspace should read." } }, - "serviceEndpointPolicies": { - "type": "array", - "defaultValue": [], + "tags": { + "type": "object", "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "nullable": true } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" }, - "virtualNetwork": { + "workspace": { "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[parameters('virtualNetworkName')]" + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" }, - "subnet": { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "serviceEndpoints", - "count": "[length(parameters('serviceEndpoints'))]", - "input": { - "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" - } - } - ], - "addressPrefix": "[parameters('addressPrefix')]", - "addressPrefixes": "[parameters('addressPrefixes')]", - "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", - "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", - "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", - "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", - "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", - "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", - "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", - "sharingScope": "[parameters('sharingScope')]" + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + } } - }, - "subnet_roleAssignments": { - "copy": { - "name": "subnet_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "subnet" - ] } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource ID of the deployed storage insights configuration." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" }, - "addressPrefix": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The address prefix for the subnet." - }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "List of address prefixes for the subnet." + "description": "The resource group where the storage insight configuration is deployed." }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + "value": "[resourceGroup().name]" }, - "ipamPoolPrefixAllocations": { - "type": "array", + "name": { + "type": "string", "metadata": { - "description": "The IPAM pool prefix allocations for the subnet." + "description": "The name of the storage insights configuration." }, - "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + "value": "[parameters('name')]" } } } }, "dependsOn": [ - "virtualNetwork" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_peering_local": { + "logAnalyticsWorkspace_linkedServices": { "copy": { - "name": "virtualNetwork_peering_local", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "localVnetName": { + "logAnalyticsWorkspaceName": { "value": "[parameters('name')]" }, - "remoteVirtualNetworkResourceId": { - "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" - }, "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" - }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" - }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" - }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + "resourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + "writeAccessResourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "6939030350004475953" + "version": "0.39.26.7824", + "templateHash": "14482465616812596213" }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." }, "parameters": { - "name": { + "logAnalyticsWorkspaceName": { "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "localVnetName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + "description": "Required. Name of the link." } }, - "remoteVirtualNetworkResourceId": { + "resourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." } }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, + "writeAccessResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." } }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, + "tags": { + "type": "object", "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true } }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" } } - ], + }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the virtual network peering was deployed into." + "description": "The name of the deployed linked service." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the virtual network peering." + "description": "The resource ID of the deployed linked service." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" }, - "resourceId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource group where the linked service is deployed." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" + "logAnalyticsWorkspace" ] }, - "virtualNetwork_peering_remote": { + "logAnalyticsWorkspace_linkedStorageAccounts": { "copy": { - "name": "virtualNetwork_peering_remote", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" }, - "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", - "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "localVnetName": { - "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" }, "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" - }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" - }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" - }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" - }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + "storageAccountIds": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "6939030350004475953" + "version": "0.39.26.7824", + "templateHash": "14864721709229272590" }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." }, "parameters": { - "name": { + "logAnalyticsWorkspaceName": { "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "localVnetName": { + "name": { "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + "description": "Required. Name of the link." } }, - "remoteVirtualNetworkResourceId": { - "type": "string", + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + "description": "Required. Linked storage accounts resources Ids." } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": "[parameters('storageAccountIds')]" } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" + }, + "etag": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + }, + "category": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" + }, + "query": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17904092372918022238" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." } }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + "description": "Required. Name of the saved search." } }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, + "displayName": { + "type": "string", "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + "description": "Required. Display name for the search." } }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, + "category": { + "type": "string", "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." } } }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" } } - ], + }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the virtual network peering was deployed into." + "description": "The resource group where the saved search is deployed." }, "value": "[resourceGroup().name]" }, "name": { "type": "string", "metadata": { - "description": "The name of the virtual network peering." + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] + }, + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "17943947755417749524" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the virtual network peering." + "description": "The resource ID of the data export." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" } } } }, "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" + "logAnalyticsWorkspace" ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network." - }, - "value": "[parameters('name')]" - }, - "subnetNames": { - "type": "array", - "metadata": { - "description": "The names of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" - } - }, - "subnetResourceIds": { - "type": "array", - "metadata": { - "description": "The resource IDs of the deployed subnets." - }, + "logAnalyticsWorkspace_dataSources": { "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(coalesce(parameters('dataSources'), createArray()))]" }, - "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "nsgs" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.name.value]" - }, - "resourceId": { - "type": "string", - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetOutputType" - }, - "copy": { - "count": "[length(parameters('subnets'))]", - "input": { - "name": "[parameters('subnets')[copyIndex()].name]", - "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", - "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", - "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" - } - } - }, - "backendSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" - }, - "webserverfarmSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" - }, - "administrationSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" - }, - "bastionSubnetResourceId": { - "type": "string", - "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "bastionHost": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('bastionHostName')]" - }, - "skuName": { - "value": "Standard" - }, - "location": { - "value": "[parameters('location')]" - }, - "virtualNetworkResourceId": { - "value": "[reference('virtualNetwork').outputs.resourceId.value]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "publicIPAddressObject": { - "value": { - "name": "[format('pip-{0}', variables('bastionHostName'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7741601918225805390" - }, - "name": "Bastion Hosts", - "description": "This module deploys a Bastion Host." - }, - "definitions": { - "publicIPAddressObjectType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for the Public IP resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create for the Public IP resource." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable usage telemetry for the Public IP module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Idle timeout in minutes for the Public IP resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to apply to the Public IP resource." - }, - "nullable": true - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the Public IP resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" + }, + "kind": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "15360290236166491819" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" + }, + "description": "Optional. Tags to configure in the resource." + }, + "nullable": true + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "18383178824663161801" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 4, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-07-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2025-07-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10255889523646649592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" + }, + "primarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The primary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" + }, + "secondarySharedKey": { + "type": "securestring", + "metadata": { + "description": "The secondary shared key of the log analytics workspace." + }, + "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } + "description": "Resource ID of the Log Analytics workspace." }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" - } - } + "value": "[reference('workspace').outputs.resourceId.value]" }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + "name": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "description": "Name of the Log Analytics workspace." + }, + "value": "[reference('workspace').outputs.name.value]" }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } + "location": { + "type": "string", + "metadata": { + "description": "Location of the workspace." }, + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "description": "Log Analytics workspace customer ID." + }, + "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + } + }, + { + "condition": "[parameters('enableMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appi-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "retentionInDays": { + "value": 365 + }, + "kind": { + "value": "web" + }, + "disableIpMasking": { + "value": false + }, + "flowType": { + "value": "Bluefield" + }, + "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7675188203537278510" } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the Azure Bastion resource." + "description": "Name of the Application Insights component." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Azure region for the resource." } }, - "virtualNetworkResourceId": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, "metadata": { - "description": "Required. Shared services Virtual Network resource Id." + "description": "Retention period in days." } }, - "bastionSubnetPublicIpResourceId": { + "kind": { "type": "string", - "defaultValue": "", + "defaultValue": "web", "metadata": { - "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." + "description": "Application type for the component." } }, - "publicIPAddressObject": { - "$ref": "#/definitions/publicIPAddressObjectType", - "defaultValue": { - "name": "[format('{0}-pip', parameters('name'))]" - }, - "metadata": { - "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Basic", - "allowedValues": [ - "Basic", - "Developer", - "Premium", - "Standard" - ], - "metadata": { - "description": "Optional. The SKU of this Bastion Host." - } - }, - "disableCopyPaste": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." - } - }, - "enableFileCopy": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." - } - }, - "enableIpConnect": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." - } - }, - "enableKerberos": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." - } - }, - "enableShareableLink": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." - } - }, - "enableSessionRecording": { + "disableIpMasking": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." + "description": "Whether to disable IP masking." } }, - "enablePrivateOnlyBastion": { - "type": "bool", - "defaultValue": false, + "flowType": { + "type": "string", + "defaultValue": "Bluefield", "metadata": { - "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." + "description": "Flow type for the component." } }, - "scaleUnits": { - "type": "int", - "defaultValue": 2, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." + "description": "Resource ID of the Log Analytics workspace connected to the component." } }, - "roleAssignments": { + "diagnosticSettings": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Diagnostic settings to apply to the component." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. The list of Availability zones to use for the zone-redundant resources." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "Tags to apply to the resource." } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "azureBastion": { - "type": "Microsoft.Network/bastionHosts", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[coalesce(parameters('tags'), createObject())]", - "sku": { - "name": "[parameters('skuName')]" - }, - "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", - "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", - "dependsOn": [ - "publicIPAddress" - ] - }, - "azureBastion_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_diagnosticSettings": { - "copy": { - "name": "azureBastion_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_roleAssignments": { - "copy": { - "name": "azureBastion_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "publicIPAddress": { - "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "appInsights": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", + "name": "[take(format('avm.res.insights.component.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -4336,55 +4105,34 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('publicIPAddressObject').name]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('name')]" }, "location": { "value": "[parameters('location')]" }, - "lock": { - "value": "[parameters('lock')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" - }, - "ipTags": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "publicIPAddressVersion": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + "retentionInDays": { + "value": "[parameters('retentionInDays')]" }, - "publicIPAllocationMethod": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + "kind": { + "value": "[parameters('kind')]" }, - "publicIpPrefixResourceId": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" + "disableIpMasking": { + "value": "[parameters('disableIpMasking')]" }, - "roleAssignments": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + "flowType": { + "value": "[parameters('flowType')]" }, - "skuName": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + "workspaceResourceId": { + "value": "[parameters('workspaceResourceId')]" }, - "skuTier": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, "tags": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" - }, - "availabilityZones": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" + "value": "[parameters('tags')]" } }, "template": { @@ -4395,105 +4143,12 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "16564959277054027786" + "templateHash": "17358780145253914698" }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." + "name": "Application Insights", + "description": "This component deploys an Application Insights instance." }, "definitions": { - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, "diagnosticSettingFullType": { "type": "object", "properties": { @@ -4733,126 +4388,155 @@ "name": { "type": "string", "metadata": { - "description": "Required. The name of the Public IP Address." + "description": "Required. Name of the Application Insights." } }, - "publicIpPrefixResourceId": { + "applicationType": { "type": "string", - "nullable": true, + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + "description": "Optional. Application type." } }, - "publicIPAllocationMethod": { + "workspaceResourceId": { "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], "metadata": { - "description": "Optional. The public IP address allocation method." + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." } }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", "allowedValues": [ - 1, - 2, - 3 + "Enabled", + "Disabled" ], "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." } }, - "publicIPAddressVersion": { + "publicNetworkAccessForQuery": { "type": "string", - "defaultValue": "IPv4", + "defaultValue": "Enabled", "allowedValues": [ - "IPv4", - "IPv6" + "Enabled", + "Disabled" ], "metadata": { - "description": "Optional. IP address version." + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." } }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], "metadata": { - "description": "Optional. The DNS settings of the public IP address." + "description": "Optional. Retention period in days." } }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, "metadata": { - "description": "Optional. The list of tags associated with the public IP address." + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." } }, - "lock": { - "$ref": "#/definitions/lockType", + "flowType": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." } }, - "skuName": { + "requestSource": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], + "nullable": true, "metadata": { - "description": "Optional. Name of a public IP address SKU." + "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." } }, - "skuTier": { + "kind": { "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], + "defaultValue": "", "metadata": { - "description": "Optional. Tier of a public IP address SKU." + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." } }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", + "immediatePurgeDataOn30Days": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + "description": "Optional. Purge data immediately after 30 days." } }, - "deleteOption": { + "ingestionMode": { "type": "string", "nullable": true, "allowedValues": [ - "Delete", - "Detach" + "ApplicationInsights", + "ApplicationInsightsWithDiagnosticSettings", + "LogAnalytics" ], "metadata": { - "description": "Optional. The delete option for the public IP address." + "description": "Optional. Indicates the flow of the ingestion." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, "roleAssignments": { @@ -4865,30 +4549,23 @@ "description": "Optional. Array of role assignments to create." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + "source": "Microsoft.Insights/components@2020-02-02#properties/tags" }, "description": "Optional. Tags of the resource." }, "nullable": true }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, "diagnosticSettings": { "type": "array", "items": { @@ -4910,15 +4587,14 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" } }, "resources": { @@ -4926,7 +4602,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -4942,51 +4618,38 @@ } } }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2025-01-01", + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "kind": "[parameters('kind')]", "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]", + "Flow_Type": "[parameters('flowType')]", + "Request_Source": "[parameters('requestSource')]", + "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", + "IngestionMode": "[parameters('ingestionMode')]" } }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { + "appInsights_roleAssignments": { "copy": { - "name": "publicIpAddress_roleAssignments", + "name": "appInsights_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -4997,17 +4660,31 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "publicIpAddress" + "appInsights" + ] + }, + "appInsights_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "appInsights" ] }, - "publicIpAddress_diagnosticSettings": { + "appInsights_diagnosticSettings": { "copy": { - "name": "publicIpAddress_diagnosticSettings", + "name": "appInsights_diagnosticSettings", "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -5038,45 +4715,142 @@ "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "publicIpAddress" + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5059808225314360251" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "appInsights" ] } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the public IP address was deployed into." + "description": "The name of the application insights component." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the public IP address." + "description": "The resource ID of the application insights component." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" }, - "resourceId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource ID of the public IP address." + "description": "The resource group the application insights component was deployed into." }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + "value": "[resourceGroup().name]" }, - "ipAddress": { + "applicationId": { "type": "string", "metadata": { - "description": "The public IP address of the public IP address resource." + "description": "The application ID of the application insights component." }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + "value": "[reference('appInsights').AppId]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" } } } @@ -5084,54 +4858,39 @@ } }, "outputs": { - "resourceGroupName": { + "resourceId": { "type": "string", "metadata": { - "description": "The resource group the Azure Bastion was deployed into." + "description": "Resource ID of the Application Insights component." }, - "value": "[resourceGroup().name]" + "value": "[reference('appInsights').outputs.resourceId.value]" }, "name": { "type": "string", "metadata": { - "description": "The name the Azure Bastion." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID the Azure Bastion." + "description": "Name of the Application Insights component." }, - "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" + "value": "[reference('appInsights').outputs.name.value]" }, - "location": { + "connectionString": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('azureBastion', '2025-01-01', 'full').location]" - }, - "ipConfAzureBastionSubnet": { - "type": "object", - "metadata": { - "description": "The Public IPconfiguration object for the AzureBastionSubnet." + "description": "Connection string of the Application Insights component." }, - "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" + "value": "[reference('appInsights').outputs.connectionString.value]" } } } }, "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" ] }, - "jumpboxVM": { - "condition": "[parameters('enablePrivateNetworking')]", + { + "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", + "name": "[take(format('module.data-collection-rule.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -5139,10 +4898,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[variables('jumpboxVmName')]" - }, - "location": { - "value": "[parameters('location')]" + "value": "[variables('dataCollectionRulesResourceName')]" }, "tags": { "value": "[parameters('tags')]" @@ -5150,3266 +4906,1855 @@ "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "computerName": { - "value": "[take(variables('jumpboxVmName'), 15)]" - }, - "osType": { - "value": "Windows" + "location": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.location.value]" }, - "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", - "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", - "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "patchMode": { - "value": "AutomaticByPlatform" - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "value": true - }, - "maintenanceConfigurationResourceId": { - "value": "[reference('maintenanceConfiguration').outputs.resourceId.value]" - }, - "enableAutomaticUpdates": { - "value": true - }, - "encryptionAtHost": { - "value": false - }, - "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", - "imageReference": { - "value": { - "publisher": "microsoft-dsvm", - "offer": "dsvm-win-2022", - "sku": "winserver-2022", - "version": "latest" - } - }, - "osDisk": { + "dataCollectionRuleProperties": { "value": { - "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", - "caching": "ReadWrite", - "createOption": "FromImage", - "deleteOption": "Delete", - "diskSizeGB": 128, - "managedDisk": { - "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" - } - } - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-{0}', variables('jumpboxVmName'))]", - "tags": "[parameters('tags')]", - "deleteOption": "Delete", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]", - "ipConfigurations": [ + "kind": "Windows", + "dataSources": { + "performanceCounters": [ { - "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", - "subnetResourceId": "[reference('virtualNetwork').outputs.administrationSubnetResourceId.value]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), null())]" + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Processes", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Handle Count", + "\\System\\System Up Time", + "\\System\\Context Switches/sec", + "\\System\\Processor Queue Length", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pages/sec", + "\\Memory\\Page Faults/sec", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors" + ], + "name": "perfCounterDataSource60" + } + ], + "windowsEventLogs": [ + { + "name": "SecurityAuditEvents", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" + ] } ] - } - ] - }, - "extensionAadJoinConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]", - "typeHandlerVersion": "1.0", - "settings": { - "mdmId": "" - } - } - }, - "extensionAntiMalwareConfig": { - "value": { - "enabled": true, - "settings": { - "AntimalwareEnabled": "true", - "Exclusions": {}, - "RealtimeProtectionEnabled": "true", - "ScheduledScanSettings": { - "day": "7", - "isEnabled": "true", - "scanType": "Quick", - "time": "120" - } }, - "tags": "[parameters('tags')]" - } - }, - "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value, 'name', format('send-{0}', reference('logAnalyticsWorkspace').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", - "extensionNetworkWatcherAgentConfig": { - "value": { - "enabled": true, - "tags": "[parameters('tags')]" + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]", + "name": "[variables('dcrLogAnalyticsDestinationName')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Microsoft-Perf" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Perf" + }, + { + "streams": [ + "Microsoft-Event" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ], + "transformKql": "source", + "outputStream": "Microsoft-Event" + } + ] } } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17174537341033050778" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." + "version": "0.42.1.51946", + "templateHash": "6345941552527061617" + } }, - "definitions": { - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "diffDiskSettings": { - "type": "object", - "properties": { - "placement": { - "type": "string", - "allowedValues": [ - "CacheDisk", - "NvmeDisk", - "ResourceDisk" - ], - "metadata": { - "description": "Required. Specifies the ephemeral disk placement for the operating system disk." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - }, + "parameters": { + "name": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type describing an OS disk." + "description": "Name of the data collection rule." } }, - "dataDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." - } - }, - "diskIOPSReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." - } - }, - "diskMBpsReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" - }, - "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." - }, - "nullable": true - } - }, + "location": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type describing a data disk." + "description": "Azure region for the resource." } }, - "publicKeyType": { + "tags": { "type": "object", - "properties": { - "keyData": { - "type": "string", - "metadata": { - "description": "Required. Specifies the SSH public key data used to authenticate through ssh." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." - } - } + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "nicConfigurationType": { + "dataCollectionRuleProperties": { "type": "object", + "metadata": { + "description": "Properties block for the data collection rule." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.data-collection-rule.{0}', parameters('name')), 64)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the NIC configuration." - } - }, - "nicSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The suffix to append to the NIC name." - } - }, - "enableIPForwarding": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify what happens to the network interface when the VM is deleted." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" }, - "nullable": true, - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" + "location": { + "value": "[parameters('location')]" }, - "metadata": { - "description": "Required. The IP configurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags of the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "tags": { + "value": "[parameters('tags')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the NIC configuration." - } - }, - "imageReferenceType": { - "type": "object", - "properties": { - "communityGalleryImageId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." + "dataCollectionRuleProperties": { + "value": "[parameters('dataCollectionRuleProperties')]" } }, - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the image reference." - } - }, - "offer": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The image publisher." - } - }, - "sku": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The SKU of the image." - } - }, - "version": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." - } - }, - "sharedGalleryImageId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the image reference." - } - }, - "planType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the plan." - } - }, - "product": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the product of the image from the marketplace." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher ID." - } - }, - "promotionCode": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The promotion code." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Specifies information about the marketplace image used to create the virtual machine." - } - }, - "autoShutDownConfigType": { - "type": "object", - "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the auto shutdown configuration." - } - }, - "timeZone": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." - } - }, - "dailyRecurrenceTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time of day the schedule will occur." - } - }, - "notificationSettings": { - "type": "object", - "properties": { - "status": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. The status of the notification settings." - } - }, - "emailRecipient": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." - } + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2441324888126124697" }, - "notificationLocale": { - "type": "string", - "nullable": true, + "name": "Data Collection Rules", + "description": "This module deploys a Data Collection Rule." + }, + "definitions": { + "dataCollectionRulePropertiesType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Linux": { + "$ref": "#/definitions/linuxDcrPropertiesType" + }, + "Windows": { + "$ref": "#/definitions/windowsDcrPropertiesType" + }, + "All": { + "$ref": "#/definitions/allPlatformsDcrPropertiesType" + }, + "AgentSettings": { + "$ref": "#/definitions/agentSettingsDcrPropertiesType" + }, + "Direct": { + "$ref": "#/definitions/directDcrPropertiesType" + }, + "WorkspaceTransforms": { + "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" + }, + "PlatformTelemetry": { + "$ref": "#/definitions/platformTelemetryDcrPropertiesType" + } + } + }, "metadata": { - "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + "__bicep_export!": true, + "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." } }, - "webhookUrl": { - "type": "string", - "nullable": true, + "linuxDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Linux" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, "metadata": { - "description": "Optional. The webhook URL to which the notification will be sent." + "description": "The type for the properties of the 'Linux' data collection rule." } }, - "timeInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The time in minutes before shutdown to send notifications." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the schedule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the configuration profile." - } - }, - "vaultSecretGroupType": { - "type": "object", - "properties": { - "sourceVault": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." - } - }, - "vaultCertificates": { - "type": "array", - "items": { - "type": "object", - "properties": { - "certificateStore": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + "windowsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Windows" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } } }, - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of key vault references in SourceVault which contain certificates." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the set of certificates that should be installed onto the virtual machine." - } - }, - "vmGalleryApplicationType": { - "type": "object", - "properties": { - "packageReferenceId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." - } - }, - "configurationReference": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." - } - }, - "order": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the order in which the packages have to be installed." - } - }, - "tags": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies a passthrough value for more generic context." - } - }, - "treatFailureAsDeploymentFailure": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the gallery application that should be made available to the VM/VMSS." - } - }, - "additionalUnattendContentType": { - "type": "object", - "properties": { - "settingName": { - "type": "string", - "allowedValues": [ - "AutoLogon", - "FirstLogonCommands" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the name of the setting to which the content applies." - } - }, - "content": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." - } - }, - "winRMListenerType": { - "type": "object", - "properties": { - "certificateUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "Http", - "Https" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the protocol of WinRM listener." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing a Windows Remote Management listener." - } - }, - "nicConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NIC configuration." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "Required. List of IP configurations of the NIC configuration." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing the network interface configuration output." - } - }, - "extensionCustomScriptConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." - } - }, - "typeHandlerVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + "description": "The type for the properties of the 'Windows' data collection rule." } }, - "fileUris": { - "type": "array", - "items": { - "type": "string" + "allPlatformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" + }, + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Optional. Declaration of custom streams used in this rule." + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "protectedSettings": { - "type": "secureObject", - "properties": { - "commandToExecute": { - "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." + "description": "The type for the properties of the data collection rule of the kind 'All'." } }, - "storageAccountName": { - "type": "string", - "nullable": true, + "agentSettingsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AgentSettings" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "agentSettings": { + "$ref": "#/definitions/agentSettingsType", + "metadata": { + "description": "Required. Agent settings used to modify agent behavior on a given host." + } + } + }, "metadata": { - "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." + "description": "The type for the properties of the 'AgentSettings' data collection rule." } }, - "storageAccountKey": { - "type": "string", - "nullable": true, + "agentSettingsType": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agentSettingType" + }, + "metadata": { + "description": "Required. All the settings that are applicable to the logs agent (AMA)." + } + } + }, "metadata": { - "description": "Optional. The access key of the storage account." + "description": "The type for the agent settings." } }, - "managedIdentityResourceId": { - "type": "string", - "nullable": true, + "agentSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "MaxDiskQuotaInMB", + "UseTimeReceivedForForwardedEvents" + ], + "metadata": { + "description": "Required. The name of the agent setting." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the agent setting." + } + } + }, "metadata": { - "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." + "description": "The type for the (single) agent setting." } }, - "fileUris": { - "type": "array", - "items": { - "type": "string" + "directDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Direct" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" + }, + "description": "Required. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. URLs for files to be downloaded." + "description": "The type for the properties of the 'Direct' data collection rule." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." - } - }, - "supressFailures": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + "workspaceTransformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "WorkspaceTransforms" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." + } + }, + "destinations": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" + }, + "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + }, + "metadata": { + "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." + } }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a 'CustomScriptExtension' extension." - } - }, - "_1.applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." + "platformTelemetryDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "PlatformTelemetry" + ], + "metadata": { + "description": "Required. The kind of the resource." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "dataSources": { + "type": "object", + "properties": { + "platformTelemetry": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" + }, + "description": "Required. The list of platform telemetry configurations." + } } }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "destinations": { + "type": "object", + "properties": { + "logAnalytics": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" + }, + "description": "Optional. The list of Log Analytics destinations." + }, + "nullable": true + }, + "storageAccounts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" + }, + "description": "Optional. The list of Storage Account destinations." + }, + "nullable": true + }, + "eventHubs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" + }, + "description": "Optional. The list of Event Hub destinations." + }, + "nullable": true } + }, + "metadata": { + "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" + }, + "description": "Required. The specification of data flows." } } }, - "nullable": true, "metadata": { - "description": "Optional. Backend addresses." + "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "description": "Optional. A reference to backendAddressPool resource." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "backendPort": { - "type": "int", - "nullable": true, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + "description": "Required. The name of the data collection rule. The name is case insensitive." } }, - "enableTcpReset": { - "type": "bool", - "nullable": true, + "dataCollectionRuleProperties": { + "$ref": "#/definitions/dataCollectionRulePropertiesType", "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + "description": "Required. The kind of data collection rule." } }, - "frontendIPConfiguration": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. A reference to frontend IP addresses." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "frontendPort": { - "type": "int", - "nullable": true, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + "description": "Optional. Location for all Resources." } }, - "frontendPortRangeStart": { - "type": "int", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + "description": "Optional. The lock settings of the service." } }, - "frontendPortRangeEnd": { - "type": "int", + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + "description": "Optional. The managed identity definition for this resource." } }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." + "description": "Optional. Array of role assignments to create." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true } }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_1.virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "_2.ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } - } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", + "enableReferencedModulesTelemetry": false }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "_2.dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dataCollectionRule": { + "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('dataCollectionRuleProperties').kind]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRuleAll": { + "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRule_conditionalScopeLock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", + "lock": { + "value": "[parameters('lock')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2876136109547890997" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "dataCollectionRuleName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + } + } + }, + "resources": { + "dataCollectionRule": { + "existing": true, + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dataCollectionRuleName')]" + }, + "dataCollectionRule_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + } + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + }, + "dataCollectionRule_roleAssignments": { + "copy": { + "name": "dataCollectionRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", + "name": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14634305923902101494" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource." + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dataCollectionRule was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" + }, + "endpoints": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", + "output": true + }, + "description": "The endpoints of the dataCollectionRule, if created." + }, + "nullable": true, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" + }, + "immutableId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The ImmutableId of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" + } + } } } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the data collection rule." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.insights.data-collection-rule.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "_2.ipTagType": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the data collection rule." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.insights.data-collection-rule.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "addressPrefixes": { + "value": [ + "10.0.0.0/8" + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "resourceSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "10323079586505814920" + } + }, + "definitions": { + "subnetOutputType": { "type": "object", "properties": { - "ipTagType": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the subnet." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the subnet." + } + }, + "nsgName": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The IP tag type." + "description": "The name of the associated NSG, if any." } }, - "tag": { + "nsgResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The IP tag." + "description": "The resource ID of the associated NSG, if any." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } + "__bicep_export!": true, + "description": "Subnet output type" } }, - "_3.diagnosticSettingFullType": { + "subnetType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "description": "Required. The name of the subnet." } }, - "logCategoriesAndGroups": { + "addressPrefixes": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "type": "string" }, - "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. Address prefixes for the subnet." } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, + "delegation": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Optional. Delegation for the subnet." } }, - "logAnalyticsDestinationType": { + "privateEndpointNetworkPolicies": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_3.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_3.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_4.publicIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Public IP Address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout in minutes." - } - }, - "lock": { - "$ref": "#/definitions/_3.lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the public IP address." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "ddosSettings": { - "$ref": "#/definitions/_2.ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "dnsSettings": { - "$ref": "#/definitions/_2.dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" ], "nullable": true, "metadata": { - "description": "Optional. The public IP address version." + "description": "Optional. Private endpoint network policies." } }, - "publicIPAllocationMethod": { + "privateLinkServiceNetworkPolicies": { "type": "string", "allowedValues": [ - "Dynamic", - "Static" + "Disabled", + "Enabled" ], "nullable": true, "metadata": { - "description": "Optional. The public IP address allocation method." + "description": "Optional. Private link service network policies." } }, - "publicIpPrefixResourceId": { - "type": "string", + "networkSecurityGroup": { + "$ref": "#/definitions/networkSecurityGroupType", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + "description": "Optional. NSG configuration for the subnet." } }, - "publicIpNameSuffix": { + "routeTableResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name suffix of the public IP address resource." + "description": "Optional. Route table resource ID." } }, - "roleAssignments": { + "serviceEndpointPolicies": { "type": "array", "items": { - "$ref": "#/definitions/_3.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU tier of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." + "type": "object" }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], "nullable": true, "metadata": { - "description": "Optional. The zones of the public IP address." + "description": "Optional. Service endpoint policies." } }, - "ipTags": { + "serviceEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/_2.ipTagType" + "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. The list of tags associated with the public IP address." + "description": "Optional. Service endpoints to enable." } }, - "enableTelemetry": { + "defaultOutboundAccess": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." + "description": "Optional. Disable default outbound connectivity." } } }, "metadata": { - "description": "The type for the public IP address configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } + "__bicep_export!": true, + "description": "Subnet configuration type" } }, - "diagnosticSettingFullType": { + "networkSecurityGroupType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. The name of the NSG." } }, - "metricCategories": { + "securityRules": { "type": "array", "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "type": "object" }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Required. Security rules for the NSG." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "NSG configuration type" + } + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." } }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Azure region for the resource." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Address prefixes for the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "defaultValue": [ + { + "name": "backend", + "addressPrefixes": [ + "10.0.0.0/27" ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." + "networkSecurityGroup": { + "name": "nsg-backend", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] } }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer backend address pools." + { + "name": "webserverfarm", + "addressPrefixes": [ + "10.0.4.0/27" + ], + "delegation": "Microsoft.Web/serverfarms", + "privateEndpointNetworkPolicies": "Enabled", + "privateLinkServiceNetworkPolicies": "Enabled", + "networkSecurityGroup": { + "name": "nsg-webserverfarm", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] } }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application security groups." + { + "name": "administration", + "addressPrefixes": [ + "10.0.0.32/27" + ], + "networkSecurityGroup": { + "name": "nsg-administration", + "securityRules": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] } }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application gateway backend address pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/_1.subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The gateway load balancer settings." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer inbound NAT rules." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address version." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The virtual network taps." - } - }, - "pipConfiguration": { - "$ref": "#/definitions/_4.publicIPConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The public IP address configuration." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/_3.diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "description": "The type for the IP configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/nic-configuration.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "description": "The type for the network interface IP configuration output.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" + { + "name": "AzureBastionSubnet", + "addressPrefixes": [ + "10.0.0.64/26" ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." + "networkSecurityGroup": { + "name": "nsg-bastion", + "securityRules": [ + { + "name": "AllowGatewayManager", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2702, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "GatewayManager", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowHttpsInBound", + "properties": { + "access": "Allow", + "direction": "Inbound", + "priority": 2703, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*" + } + }, + { + "name": "AllowSshRdpOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 100, + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AllowAzureCloudOutbound", + "properties": { + "access": "Allow", + "direction": "Outbound", + "priority": 110, + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "443", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "AzureCloud" + } + } + ] } } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" - }, - "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." - }, - "nullable": true - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" - }, - "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." - }, - "nullable": true - }, - "plan": { - "$ref": "#/definitions/planType", - "nullable": true, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "type": "array", - "items": { - "$ref": "#/definitions/dataDiskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "hibernationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables hibernation capability on the VM." - } - }, - "adminUsername": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." - } - }, - "userData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "items": { - "$ref": "#/definitions/vaultSecretGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "evictionPolicy": { - "type": "string", - "defaultValue": "Deallocate", - "allowedValues": [ - "Deallocate", - "Delete" - ], - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "publicKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/publicKeyType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "galleryApplications": { - "type": "array", - "items": { - "$ref": "#/definitions/vmGalleryApplicationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." - } - }, - "availabilityZone": { - "type": "int", - "allowedValues": [ - -1, - 1, - 2, - 3 ], "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." - } - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationType" - }, - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Recovery service vault name to add VMs to backup." - } - }, - "backupVaultResourceGroup": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." - } - }, - "backupPolicyName": { - "type": "string", - "defaultValue": "DefaultPolicy", - "metadata": { - "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + "description": "Subnet configurations." } }, - "autoShutdownConfig": { - "$ref": "#/definitions/autoShutDownConfigType", + "tags": { + "type": "object", "defaultValue": {}, "metadata": { - "description": "Optional. The configuration for auto-shutdown." + "description": "Tags to apply to the resources." } }, - "maintenanceConfigurationResourceId": { + "logAnalyticsWorkspaceId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The resource Id of a maintenance configuration for this VM." + "description": "Resource ID of the Log Analytics Workspace for diagnostics." } }, - "allowExtensionOperations": { + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "extensionDomainJoinConfig": { - "type": "secureObject", - "defaultValue": {}, + "resourceSuffix": { + "type": "string", "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAntiMalwareConfig": { - "type": "object", - "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", - "metadata": { - "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionMonitoringAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "dataCollectionRuleAssociations": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionDependencyAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNetworkWatcherAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "$ref": "#/definitions/extensionCustomScriptConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionHostPoolRegistration": { - "type": "secureObject", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "extensionGuestConfigurationExtension": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." - } - }, - "guestConfiguration": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." - } - }, - "extensionGuestConfigurationExtensionProtectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "disablePasswordAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether password authentication should be disabled." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "enableHotpatching": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "items": { - "$ref": "#/definitions/additionalUnattendContentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRMListeners": { - "type": "array", - "items": { - "$ref": "#/definitions/winRMListenerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - }, - "capacityReservationGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." - } - }, - "networkAccessPolicy": { - "type": "string", - "defaultValue": "DenyAll", - "allowedValues": [ - "AllowAll", - "AllowPrivate", - "DenyAll" - ], - "metadata": { - "description": "Optional. Policy for accessing the disk via network." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Policy for controlling export on the disk." + "description": "Suffix for resource naming." } } }, "variables": { - "copy": [ - { - "name": "publicKeysFormatted", - "count": "[length(parameters('publicKeys'))]", - "input": { - "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", - "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" - } - }, - { - "name": "additionalUnattendContentFormatted", - "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", - "input": { - "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", - "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", - "componentName": "Microsoft-Windows-Shell-Setup", - "passName": "OobeSystem" - } - }, - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "linuxConfiguration": { - "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", - "ssh": { - "publicKeys": "[variables('publicKeysFormatted')]" - }, - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" - }, - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", - "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", - "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", - "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", - "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", - "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", - "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", - "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", - "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", - "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", - "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", - "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", - "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" - }, - "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", - "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" + "name": "[format('vnet-{0}', parameters('solutionName'))]" }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "managedDataDisks": { - "copy": { - "name": "managedDataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" - }, - "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", - "type": "Microsoft.Compute/disks", - "apiVersion": "2025-01-02", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", - "location": "[parameters('location')]", - "sku": { - "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" - }, - "properties": { - "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", - "creationData": { - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" - }, - "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", - "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "networkAccessPolicy": "[parameters('networkAccessPolicy')]" - }, - "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", - "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", - "plan": "[parameters('plan')]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", - "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", - "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", - "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", - "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", - "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", - "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", - "osType": "[parameters('osType')]", - "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", - "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", - "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", - "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", - "managedDisk": { - "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", - "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", - "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", - "hibernationEnabled": "[parameters('hibernationEnabled')]" - }, - "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" - } - } - ] - }, - "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", - "licenseType": "[parameters('licenseType')]", - "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" - }, - "dependsOn": [ - "managedDataDisks", - "vm_nic" - ] - }, - "vm_configurationAssignment": { - "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", - "type": "Microsoft.Maintenance/configurationAssignments", - "apiVersion": "2023-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[format('{0}assignment', parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", - "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_autoShutdownConfiguration": { - "condition": "[not(empty(parameters('autoShutdownConfig')))]", - "type": "Microsoft.DevTestLab/schedules", - "apiVersion": "2018-09-15", - "name": "[format('shutdown-computevm-{0}', parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", - "properties": { - "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", - "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "taskType": "ComputeVmShutdownTask", - "dailyRecurrence": { - "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" - }, - "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", - "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_dataCollectionRuleAssociations": { - "copy": { - "name": "vm_dataCollectionRuleAssociations", - "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" - }, - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Insights/dataCollectionRuleAssociations", - "apiVersion": "2024-03-11", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", - "properties": { - "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "cseIdentity": { - "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", - "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" - }, - "AzureWindowsBaseline": { - "condition": "[not(empty(parameters('guestConfiguration')))]", - "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", - "apiVersion": "2024-04-05", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", - "location": "[parameters('location')]", - "properties": { - "guestConfiguration": "[parameters('guestConfiguration')]" - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - }, - "vm_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_roleAssignments": { - "copy": { - "name": "vm_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { + "nsgs": { "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" + "name": "nsgs", + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 }, + "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.network.nsg.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "networkInterfaceName": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" - }, - "virtualMachineName": { - "value": "[parameters('name')]" + "name": { + "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix'))]" }, "location": { "value": "[parameters('location')]" }, - "enableIPForwarding": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" - }, - "enableAcceleratedNetworking": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" - }, - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" - }, - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "lock": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" + "securityRules": { + "value": "[tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'securityRules')]" }, "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -8420,500 +6765,180 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "5982155361487304817" - } + "templateHash": "7311263652424030280" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG)." }, "definitions": { - "publicIPConfigurationType": { + "securityRuleType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Public IP Address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Diagnostic settings for the public IP address." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout in minutes." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the public IP address." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "publicIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address version." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIpNameSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name suffix of the public IP address resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "skuName": { - "type": "string", - "allowedValues": [ - "Basic", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU name of the public IP address." - } - }, - "skuTier": { - "type": "string", - "allowedValues": [ - "Global", - "Regional" - ], - "nullable": true, "metadata": { - "description": "Optional. The SKU tier of the public IP address." + "description": "Required. The name of the security rule." } }, - "tags": { + "properties": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + "properties": { + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. Whether network traffic is allowed or denied." + } }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "availabilityZones": { - "type": "array", - "allowedValues": [ - 1, - 2, - 3 - ], - "nullable": true, - "metadata": { - "description": "Optional. The zones of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the public IP address configuration." - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer backend address pools." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application security groups." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The application gateway backend address pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The gateway load balancer settings." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The load balancer inbound NAT rules." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address version." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The virtual network taps." - } - }, - "pipConfiguration": { - "$ref": "#/definitions/publicIPConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The public IP address configuration." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the IP configuration." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the security rule." + } }, - "description": "Optional. The tags of the public IP address." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for the module." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the IP configuration." - } - }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { + "destinationAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { "type": "array", "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } + "type": "string" }, "nullable": true, "metadata": { - "description": "Optional. Backend addresses." + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "description": "The type for the application gateway backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "description": "The type for the application security group.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "description": "The type for a backend address pool.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { + }, + "destinationApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as destination." + } + }, + "destinationPortRange": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 4096, + "metadata": { + "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The source port ranges." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], "metadata": { - "description": "Required. The DDoS protection policy customizations." + "description": "Required. The properties of the security rule." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } + "__bicep_export!": true, + "description": "The type of a security rule." } }, - "diagnosticSettingFullType": { + "diagnosticSettingLogsOnlyType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "description": "Optional. The name of diagnostic setting." } }, "logCategoriesAndGroups": { @@ -8949,31 +6974,6 @@ "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ @@ -9022,280 +7022,83 @@ } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "dnsSettingsType": { + "lockType": { "type": "object", "properties": { - "domainNameLabel": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + "description": "Optional. Specify the name of lock." } }, - "domainNameLabelScope": { + "kind": { "type": "string", "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" + "CanNotDelete", + "None", + "ReadOnly" ], "nullable": true, "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + "description": "Optional. Specify the type of lock." } }, - "reverseFqdn": { + "notes": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "inboundNatRuleType": { + "roleAssignmentType": { "type": "object", "properties": { - "id": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "name": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "description": "The type for the inbound NAT rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The principal type of the assigned principal ID." } }, "description": { @@ -9333,120 +7136,50 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "description": "The type for the sub resource.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" - } - } - }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "description": "The type for the virtual network tap.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } }, "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." } }, "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Optional. Location for all resources." } }, - "tags": { - "type": "object", + "securityRules": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRuleType" + }, "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." } }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { + "flushConnection": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } }, - "dnsServers": { + "diagnosticSettings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" }, - "defaultValue": [] - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." + "description": "Optional. The diagnostic settings of the service." } }, "lock": { @@ -9456,17942 +7189,1155 @@ "description": "Optional. The lock settings of the service." } }, - "diagnosticSettings": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkSecurityGroups@2025-05-01#properties/tags" + }, + "description": "Optional. Tags of the NSG resource." }, - "nullable": true, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "networkInterface_publicIPAddresses": { - "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" - }, - "diagnosticSettings": { - "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" - }, - "ddosSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" - }, - "publicIPAddressVersion": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" - }, - "publicIPAllocationMethod": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" - }, - "publicIpPrefixResourceId": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" - }, - "roleAssignments": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" - }, - "skuName": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" - }, - "skuTier": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "availabilityZones": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" - }, - "enableTelemetry": { - "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" - }, - "ipTags": { - "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" - } - }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5349747633189946992" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(coalesce(parameters('securityRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", + "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", + "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", + "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", + "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", + "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", + "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", + "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", + "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", + "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", + "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", + "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", + "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", + "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", + "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" } - }, - "roleAssignmentType": { + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { + "copy": { + "name": "networkSecurityGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2025-05-01', 'full').location]" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.virtual-network.{0}', variables('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "addressPrefixes": { + "value": "[parameters('addressPrefixes')]" + }, + "subnets": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('subnets'))]", + "input": "[createObject('name', parameters('subnets')[copyIndex('value')].name, 'addressPrefixes', tryGet(parameters('subnets')[copyIndex('value')], 'addressPrefixes'), 'networkSecurityGroupResourceId', if(not(empty(tryGet(parameters('subnets')[copyIndex('value')], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex('value'))).outputs.resourceId.value, null()), 'privateEndpointNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateEndpointNetworkPolicies'), 'privateLinkServiceNetworkPolicies', tryGet(parameters('subnets')[copyIndex('value')], 'privateLinkServiceNetworkPolicies'), 'delegation', tryGet(parameters('subnets')[copyIndex('value')], 'delegation'))]" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "name": "vnetDiagnostics", + "workspaceResourceId": "[parameters('logAnalyticsWorkspaceId')]", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs", + "enabled": true + } + ], + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11272001757446231867" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet)." + }, + "definitions": { + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "prefixItems": [ + { "type": "object", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, + "pool": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the IPAM pool." + } + } + }, "metadata": { - "description": "Optional. Version of the condition." + "description": "Required. The Resource ID of the IPAM pool." } }, - "delegatedManagedIdentityResourceId": { + "numberOfIpAddresses": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Required. Number of IP addresses allocated from the pool." } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty and the VNet address space configured to use IPAM Pool." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" - }, - "description": "Optional. The public IP address allocation method." - }, - "defaultValue": "Static" - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" - }, - "description": "Optional. IP address version." - }, - "defaultValue": "IPv4" - }, - "dnsSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" - }, - "description": "Optional. The DNS settings of the public IP address." - }, - "nullable": true - }, - "ipTags": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" - }, - "description": "Optional. The list of tags associated with the public IP address." - }, - "nullable": true - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" - }, - "description": "Optional. Name of a public IP address SKU." - }, - "defaultValue": "Standard" - }, - "skuTier": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" - }, - "description": "Optional. Tier of a public IP address SKU." - }, - "defaultValue": "Regional" - }, - "ddosSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" - }, - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - }, - "nullable": true - }, - "deleteOption": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" - }, - "description": "Optional. The delete option for the public IP address." - }, - "nullable": true - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]", - "deleteOption": "[parameters('deleteOption')]" - } - }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" - } + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." } } + }, + "metadata": { + "__bicep_export!": true } }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", + "diagnosticSettingFullType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" + } }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": { - "value": "[parameters('roleAssignments')]" + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "272838238520810437" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface." + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } }, - "definitions": { - "networkInterfaceIPConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the IP configuration." - } - }, - "privateIPAllocationMethod": { - "type": "string", - "allowedValues": [ - "Dynamic", - "Static" - ], - "nullable": true, - "metadata": { - "description": "Optional. The private IP address allocation method." - } - }, - "privateIPAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The private IP address." - } - }, - "publicIPAddressResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the public IP address." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the subnet." - } - }, - "loadBalancerBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/backendAddressPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of load balancer backend address pools." - } - }, - "loadBalancerInboundNatRules": { - "type": "array", - "items": { - "$ref": "#/definitions/inboundNatRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of references of LoadBalancerInboundNatRules." - } - }, - "applicationSecurityGroups": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationSecurityGroupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the IP configuration is included." - } - }, - "applicationGatewayBackendAddressPools": { - "type": "array", - "items": { - "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Application Gateway Backend Address Pools." - } - }, - "gatewayLoadBalancer": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. The reference to gateway load balancer frontend IP." - } - }, - "privateIPAddressVersion": { - "type": "string", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." - } - }, - "virtualNetworkTaps": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkTapType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The reference to Virtual Network Taps." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The resource ID of the deployed resource." - } - }, - "backendAddressPoolType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backend address pool." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The properties of the backend address pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backend address pool." - } - }, - "applicationSecurityGroupType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the application security group." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the application security group." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application security group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the application security group." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the application security group." - } - }, - "applicationGatewayBackendAddressPoolsType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the backend address pool." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. IP address of the backend address." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN of the backend address." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Backend addresses." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the application gateway backend address pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the application gateway backend address pool." - } - }, - "subResourceType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the sub resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the sub resource." - } - }, - "inboundNatRuleType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the inbound NAT rule." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." - } - }, - "properties": { - "type": "object", - "properties": { - "backendAddressPool": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to backendAddressPool resource." - } - }, - "backendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." - } - }, - "enableFloatingIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." - } - }, - "enableTcpReset": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." - } - }, - "frontendIPConfiguration": { - "$ref": "#/definitions/subResourceType", - "nullable": true, - "metadata": { - "description": "Optional. A reference to frontend IP addresses." - } - }, - "frontendPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeStart": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "frontendPortRangeEnd": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "All", - "Tcp", - "Udp" - ], - "nullable": true, - "metadata": { - "description": "Optional. The reference to the transport protocol used by the load balancing rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Properties of the inbound NAT rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the inbound NAT rule." - } - }, - "virtualNetworkTapType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the virtual network tap." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the virtual network tap." - } - }, - "properties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Properties of the virtual network tap." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the virtual network tap." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network tap." - } - }, - "networkInterfaceIPConfigurationOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the IP configuration." - } - }, - "privateIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The private IP address." - } - }, - "publicIP": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The public IP address." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network interface IP configuration output." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationType" - }, - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "publicIp": { - "copy": { - "name": "publicIp", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", - "existing": true, - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2024-05-01", - "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", - "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", - "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", - "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", - "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", - "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", - "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", - "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed resource." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkInterface', '2024-05-01', 'full').location]" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "The list of IP configurations of the network interface." - }, - "copy": { - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", - "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", - "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" - } - } - } - } - } - }, - "dependsOn": [ - "networkInterface_publicIPAddresses" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the network interface." - }, - "value": "[reference('networkInterface').outputs.name.value]" - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" - }, - "metadata": { - "description": "The list of IP configurations of the network interface." - }, - "value": "[reference('networkInterface').outputs.ipConfigurations.value]" - } - } - } - } - }, - "vm_domainJoinExtension": { - "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_domainJoinExtension" - ] - }, - "vm_microsoftAntiMalwareExtension": { - "condition": "[parameters('extensionAntiMalwareConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": { - "value": "IaaSAntimalware" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_azureMonitorAgentExtension": { - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitor" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_microsoftAntiMalwareExtension" - ] - }, - "vm_dependencyAgentExtension": { - "condition": "[parameters('extensionDependencyAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitoring.DependencyAgent" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" - }, - "settings": { - "value": { - "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "vm_networkWatcherAgentExtension": { - "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.NetworkWatcher" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_dependencyAgentExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_networkWatcherAgentExtension" - ] - }, - "vm_customScriptExtension": { - "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" - }, - "provisionAfterExtensions": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettingsFromKeyVault": { - "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" - }, - "settings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" - }, - "protectedSettings": { - "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "cseIdentity", - "vm" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_customScriptExtension" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - }, - "vm_hostPoolRegistrationExtension": { - "condition": "[parameters('extensionHostPoolRegistration').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.PowerShell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": { - "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", - "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", - "properties": { - "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", - "aadJoin": true - } - } - }, - "protectedSettings": { - "value": { - "properties": { - "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" - } - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_nvidiaGpuDriverWindowsExtension" - ] - }, - "vm_azureGuestConfigurationExtension": { - "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.GuestConfiguration" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" - }, - "protectedSettings": { - "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "3581830278162851734" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "protectedSettingsFromKeyVault": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" - }, - "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." - }, - "nullable": true - }, - "provisionAfterExtensions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" - }, - "description": "Optional. Collection of extension names after which this extension needs to be provisioned." - }, - "nullable": true - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "settings": "[parameters('settings')]", - "protectedSettings": "[parameters('protectedSettings')]", - "suppressFailures": "[parameters('supressFailures')]", - "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", - "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2024-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_hostPoolRegistrationExtension" - ] - }, - "vm_backup": { - "condition": "[not(empty(parameters('backupVaultName')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", - "resourceGroup": "[parameters('backupVaultResourceGroup')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "policyId": { - "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" - }, - "protectedItemType": { - "value": "Microsoft.Compute/virtualMachines" - }, - "protectionContainerName": { - "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" - }, - "recoveryVaultName": { - "value": "[parameters('backupVaultName')]" - }, - "sourceResourceId": { - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17448691641471706096" - }, - "name": "Recovery Service Vaults Protection Container Protected Item", - "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the resource." - } - }, - "protectionContainerName": { - "type": "string", - "metadata": { - "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." - } - }, - "recoveryVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "protectedItemType": { - "type": "string", - "allowedValues": [ - "AzureFileShareProtectedItem", - "AzureVmWorkloadSAPAseDatabase", - "AzureVmWorkloadSAPHanaDatabase", - "AzureVmWorkloadSQLDatabase", - "DPMProtectedItem", - "GenericProtectedItem", - "MabFileFolderProtectedItem", - "Microsoft.ClassicCompute/virtualMachines", - "Microsoft.Compute/virtualMachines", - "Microsoft.Sql/servers/databases" - ], - "metadata": { - "description": "Required. The backup item type." - } - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Required. ID of the backup policy with which this item is backed up." - } - }, - "sourceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource to back up." - } - } - }, - "resources": [ - { - "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", - "apiVersion": "2025-02-01", - "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "protectedItemType": "[parameters('protectedItemType')]", - "policyId": "[parameters('policyId')]", - "sourceResourceId": "[parameters('sourceResourceId')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the protected item was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the protected item." - }, - "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The Name of the protected item." - }, - "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2024-07-01', 'full').location]" - }, - "nicConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/nicConfigurationOutputType" - }, - "metadata": { - "description": "The list of NIC configurations of the virtual machine." - }, - "copy": { - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", - "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" - } - } - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "maintenanceConfiguration", - "virtualNetwork", - "windowsVmDataCollectionRules" - ] - }, - "maintenanceConfiguration": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.maintenance-configuration.{0}', variables('jumpboxVmName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('mc-{0}', variables('jumpboxVmName'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "extensionProperties": { - "value": { - "InGuestPatchMode": "User" - } - }, - "maintenanceScope": { - "value": "InGuestPatch" - }, - "maintenanceWindow": { - "value": { - "startDateTime": "2024-06-16 00:00", - "duration": "03:55", - "timeZone": "W. Europe Standard Time", - "recurEvery": "1Day" - } - }, - "visibility": { - "value": "Custom" - }, - "installPatches": { - "value": { - "rebootSetting": "IfRequired", - "windowsParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - }, - "linuxParameters": { - "classificationsToInclude": [ - "Critical", - "Security" - ] - } - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14895287194406877557" - }, - "name": "Maintenance Configurations", - "description": "This module deploys a Maintenance Configuration." - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Maintenance Configuration Name." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "extensionProperties": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" - }, - "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." - }, - "defaultValue": {} - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "maintenanceScope": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" - }, - "description": "Optional. Gets or sets maintenanceScope of the configuration." - }, - "defaultValue": "Host" - }, - "maintenanceWindow": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" - }, - "description": "Optional. Definition of a MaintenanceWindow." - }, - "defaultValue": {} - }, - "namespace": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Gets or sets namespace of the resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" - }, - "description": "Optional. Gets or sets tags of the resource." - }, - "nullable": true - }, - "visibility": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" - }, - "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." - }, - "nullable": true - }, - "installPatches": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" - }, - "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." - }, - "defaultValue": {} - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "maintenanceConfiguration": { - "type": "Microsoft.Maintenance/maintenanceConfigurations", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "extensionProperties": "[parameters('extensionProperties')]", - "maintenanceScope": "[parameters('maintenanceScope')]", - "maintenanceWindow": "[parameters('maintenanceWindow')]", - "namespace": "[parameters('namespace')]", - "visibility": "[parameters('visibility')]", - "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" - } - }, - "maintenanceConfiguration_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - }, - "maintenanceConfiguration_roleAssignments": { - "copy": { - "name": "maintenanceConfiguration_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "maintenanceConfiguration" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Maintenance Configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Maintenance Configuration." - }, - "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Maintenance Configuration was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the Maintenance Configuration was created in." - }, - "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" - } - } - } - } - }, - "windowsVmDataCollectionRules": { - "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.data-collection-rule.{0}', variables('dataCollectionRulesResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('dataCollectionRulesResourceName')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "location": { - "value": "[reference('logAnalyticsWorkspace').outputs.location.value]" - }, - "dataCollectionRuleProperties": { - "value": { - "kind": "Windows", - "dataSources": { - "performanceCounters": [ - { - "streams": [ - "Microsoft-Perf" - ], - "samplingFrequencyInSeconds": 60, - "counterSpecifiers": [ - "\\Processor Information(_Total)\\% Processor Time", - "\\Processor Information(_Total)\\% Privileged Time", - "\\Processor Information(_Total)\\% User Time", - "\\Processor Information(_Total)\\Processor Frequency", - "\\System\\Processes", - "\\Process(_Total)\\Thread Count", - "\\Process(_Total)\\Handle Count", - "\\System\\System Up Time", - "\\System\\Context Switches/sec", - "\\System\\Processor Queue Length", - "\\Memory\\% Committed Bytes In Use", - "\\Memory\\Available Bytes", - "\\Memory\\Committed Bytes", - "\\Memory\\Cache Bytes", - "\\Memory\\Pool Paged Bytes", - "\\Memory\\Pool Nonpaged Bytes", - "\\Memory\\Pages/sec", - "\\Memory\\Page Faults/sec", - "\\Process(_Total)\\Working Set", - "\\Process(_Total)\\Working Set - Private", - "\\LogicalDisk(_Total)\\% Disk Time", - "\\LogicalDisk(_Total)\\% Disk Read Time", - "\\LogicalDisk(_Total)\\% Disk Write Time", - "\\LogicalDisk(_Total)\\% Idle Time", - "\\LogicalDisk(_Total)\\Disk Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", - "\\LogicalDisk(_Total)\\Disk Transfers/sec", - "\\LogicalDisk(_Total)\\Disk Reads/sec", - "\\LogicalDisk(_Total)\\Disk Writes/sec", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", - "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", - "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", - "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", - "\\LogicalDisk(_Total)\\% Free Space", - "\\LogicalDisk(_Total)\\Free Megabytes", - "\\Network Interface(*)\\Bytes Total/sec", - "\\Network Interface(*)\\Bytes Sent/sec", - "\\Network Interface(*)\\Bytes Received/sec", - "\\Network Interface(*)\\Packets/sec", - "\\Network Interface(*)\\Packets Sent/sec", - "\\Network Interface(*)\\Packets Received/sec", - "\\Network Interface(*)\\Packets Outbound Errors", - "\\Network Interface(*)\\Packets Received Errors" - ], - "name": "perfCounterDataSource60" - } - ], - "windowsEventLogs": [ - { - "name": "SecurityAuditEvents", - "streams": [ - "Microsoft-Event" - ], - "xPathQueries": [ - "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" - ] - } - ] - }, - "destinations": { - "logAnalytics": [ - { - "workspaceResourceId": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]", - "name": "[variables('dcrLogAnalyticsDestinationName')]" - } - ] - }, - "dataFlows": [ - { - "streams": [ - "Microsoft-Perf" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Perf" - }, - { - "streams": [ - "Microsoft-Event" - ], - "destinations": [ - "[variables('dcrLogAnalyticsDestinationName')]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Event" - } - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2441324888126124697" - }, - "name": "Data Collection Rules", - "description": "This module deploys a Data Collection Rule." - }, - "definitions": { - "dataCollectionRulePropertiesType": { - "type": "object", - "discriminator": { - "propertyName": "kind", - "mapping": { - "Linux": { - "$ref": "#/definitions/linuxDcrPropertiesType" - }, - "Windows": { - "$ref": "#/definitions/windowsDcrPropertiesType" - }, - "All": { - "$ref": "#/definitions/allPlatformsDcrPropertiesType" - }, - "AgentSettings": { - "$ref": "#/definitions/agentSettingsDcrPropertiesType" - }, - "Direct": { - "$ref": "#/definitions/directDcrPropertiesType" - }, - "WorkspaceTransforms": { - "$ref": "#/definitions/workspaceTransformsDcrPropertiesType" - }, - "PlatformTelemetry": { - "$ref": "#/definitions/platformTelemetryDcrPropertiesType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Required. The type for data collection rule properties. Depending on the kind, the properties will be different." - } - }, - "linuxDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Linux" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Linux' data collection rule." - } - }, - "windowsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Windows" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Windows' data collection rule." - } - }, - "allPlatformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "All" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataSources": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources" - }, - "description": "Required. Specification of data sources that will be collected." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Optional. Declaration of custom streams used in this rule." - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the data collection rule of the kind 'All'." - } - }, - "agentSettingsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "AgentSettings" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "agentSettings": { - "$ref": "#/definitions/agentSettingsType", - "metadata": { - "description": "Required. Agent settings used to modify agent behavior on a given host." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'AgentSettings' data collection rule." - } - }, - "agentSettingsType": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "$ref": "#/definitions/agentSettingType" - }, - "metadata": { - "description": "Required. All the settings that are applicable to the logs agent (AMA)." - } - } - }, - "metadata": { - "description": "The type for the agent settings." - } - }, - "agentSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "MaxDiskQuotaInMB", - "UseTimeReceivedForForwardedEvents" - ], - "metadata": { - "description": "Required. The name of the agent setting." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. The value of the agent setting." - } - } - }, - "metadata": { - "description": "The type for the (single) agent setting." - } - }, - "directDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "Direct" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows." - } - }, - "dataCollectionEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." - } - }, - "streamDeclarations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/streamDeclarations" - }, - "description": "Required. Declaration of custom streams used in this rule." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'Direct' data collection rule." - } - }, - "workspaceTransformsDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "WorkspaceTransforms" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows. Should include a separate dataflow for each table that will have a transformation. Use a where clause in the query if only certain records should be transformed." - } - }, - "destinations": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations" - }, - "description": "Required. Specification of destinations that can be used in data flows. For WorkspaceTransforms, only one Log Analytics workspace destination is supported." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'WorkspaceTransforms' data collection rule." - } - }, - "platformTelemetryDcrPropertiesType": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "allowedValues": [ - "PlatformTelemetry" - ], - "metadata": { - "description": "Required. The kind of the resource." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description of the data collection rule." - } - }, - "dataSources": { - "type": "object", - "properties": { - "platformTelemetry": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataSources/properties/platformTelemetry" - }, - "description": "Required. The list of platform telemetry configurations." - } - } - }, - "metadata": { - "description": "Required. Specification of data sources that will be collected." - } - }, - "destinations": { - "type": "object", - "properties": { - "logAnalytics": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/logAnalytics" - }, - "description": "Optional. The list of Log Analytics destinations." - }, - "nullable": true - }, - "storageAccounts": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/storageAccounts" - }, - "description": "Optional. The list of Storage Account destinations." - }, - "nullable": true - }, - "eventHubs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/destinations/properties/eventHubs" - }, - "description": "Optional. The list of Event Hub destinations." - }, - "nullable": true - } - }, - "metadata": { - "description": "Required. Specification of destinations. Choose a single destination type of either logAnalytics, storageAccounts, or eventHubs." - } - }, - "dataFlows": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/dataFlows" - }, - "description": "Required. The specification of data flows." - } - } - }, - "metadata": { - "description": "The type for the properties of the 'PlatformTelemetry' data collection rule." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the data collection rule. The name is case insensitive." - } - }, - "dataCollectionRuleProperties": { - "$ref": "#/definitions/dataCollectionRulePropertiesType", - "metadata": { - "description": "Required. The kind of data collection rule." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(contains(createArray('Linux', 'Windows', 'All', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms', 'PlatformTelemetry'), parameters('dataCollectionRuleProperties').kind), createObject('dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations), createObject()), if(contains(createArray('Linux', 'Windows', 'All', 'Direct', 'WorkspaceTransforms'), parameters('dataCollectionRuleProperties').kind), createObject('dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "dataCollectionRule": { - "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "kind": "[parameters('dataCollectionRuleProperties').kind]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRuleAll": { - "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": "[variables('dataCollectionRulePropertiesUnion')]" - }, - "dataCollectionRule_conditionalScopeLock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-Lock', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", - "lock": { - "value": "[parameters('lock')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2876136109547890997" - } - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "dataCollectionRuleName": { - "type": "string", - "metadata": { - "description": "Required. Name of the Data Collection Rule to assign the role(s) to." - } - } - }, - "resources": { - "dataCollectionRule": { - "existing": true, - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2024-03-11", - "name": "[parameters('dataCollectionRuleName')]" - }, - "dataCollectionRule_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dataCollectionRuleName'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - } - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - }, - "dataCollectionRule_roleAssignments": { - "copy": { - "name": "dataCollectionRule_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-DCR-RoleAssignments-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceId": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))), createObject('value', resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))))]", - "name": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "14634305923902101494" - }, - "name": "Resource-scoped role assignment", - "description": "This module deploys a Role Assignment for a specific resource." - }, - "parameters": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The scope for the role assignment, fully qualified resourceId." - } - }, - "name": { - "type": "string", - "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", - "metadata": { - "description": "Optional. The unique guid name for the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition ID for the role assignment." - } - }, - "roleName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The name for the role, used for logging." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of role assignment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string" - }, - "name": { - "type": "string" - }, - "roleDefinitionId": { - "type": "string" - }, - "principalId": { - "type": "string" - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string" - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "principalType": "[[parameters('principalType')]", - "description": "[[parameters('description')]" - } - } - ], - "outputs": { - "roleAssignmentId": { - "type": "string", - "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" - } - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", - "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "Outer" - }, - "template": "[variables('$fxv#0')]", - "parameters": { - "scope": { - "value": "[parameters('resourceId')]" - }, - "name": { - "value": "[parameters('name')]" - }, - "roleDefinitionId": { - "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" - }, - "principalId": { - "value": "[parameters('principalId')]" - }, - "principalType": { - "value": "[parameters('principalType')]" - }, - "description": { - "value": "[parameters('description')]" - } - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[parameters('name')]" - }, - "roleName": { - "type": "string", - "metadata": { - "description": "The name for the role, used for logging." - }, - "value": "[parameters('roleName')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "dataCollectionRule", - "dataCollectionRuleAll" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the dataCollectionRule was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full').location, reference('dataCollectionRule', '2024-03-11', 'full').location)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2024-03-11', 'full'), null()), 'identity'), 'principalId'), tryGet(tryGet(if(not(equals(parameters('dataCollectionRuleProperties').kind, 'All')), reference('dataCollectionRule', '2024-03-11', 'full'), null()), 'identity'), 'principalId'))]" - }, - "endpoints": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/dataCollectionRules@2024-03-11#properties/properties/properties/endpoints", - "output": true - }, - "description": "The endpoints of the dataCollectionRule, if created." - }, - "nullable": true, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'endpoints'), tryGet(reference('dataCollectionRule'), 'endpoints'))]" - }, - "immutableId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The ImmutableId of the dataCollectionRule." - }, - "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(reference('dataCollectionRuleAll'), 'immutableId'), tryGet(reference('dataCollectionRule'), 'immutableId'))]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmPrivateDnsZones": { - "copy": { - "name": "avmPrivateDnsZones", - "count": "[length(variables('privateDnsZones'))]", - "mode": "serial", - "batchSize": 5 - }, - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1]), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZones')[copyIndex()]]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "virtualNetworkLinks": { - "value": [ - { - "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18337341331267624582" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone." - }, - "definitions": { - "aType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" - }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the A record." - } - }, - "aaaaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the AAAA record." - } - }, - "cnameType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. The CNAME record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the CNAME record." - } - }, - "mxType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the MX record." - } - }, - "ptrType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the PTR record." - } - }, - "soaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "soaRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" - }, - "description": "Optional. The SOA record in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SOA record." - } - }, - "srvType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "srvRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" - }, - "description": "Optional. The list of SRV records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SRV record." - } - }, - "txtType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata of the record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "txtRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" - }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the TXT record." - } - }, - "virtualNetworkLinkType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 1, - "maxLength": 80, - "metadata": { - "description": "Optional. The resource name." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the virtual network to link." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Region where the resource lives." - } - }, - "registrationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" - }, - "description": "Optional. Resource tags." - }, - "nullable": true - }, - "resolutionPolicy": { - "type": "string", - "allowedValues": [ - "Default", - "NxDomainRedirect" - ], - "nullable": true, - "metadata": { - "description": "Optional. The resolution type of the private-dns-zone fallback machanism." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network link." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "a": { - "type": "array", - "items": { - "$ref": "#/definitions/aType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of A records." - } - }, - "aaaa": { - "type": "array", - "items": { - "$ref": "#/definitions/aaaaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of AAAA records." - } - }, - "cname": { - "type": "array", - "items": { - "$ref": "#/definitions/cnameType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of CNAME records." - } - }, - "mx": { - "type": "array", - "items": { - "$ref": "#/definitions/mxType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of MX records." - } - }, - "ptr": { - "type": "array", - "items": { - "$ref": "#/definitions/ptrType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of PTR records." - } - }, - "soa": { - "type": "array", - "items": { - "$ref": "#/definitions/soaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SOA records." - } - }, - "srv": { - "type": "array", - "items": { - "$ref": "#/definitions/srvType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SRV records." - } - }, - "txt": { - "type": "array", - "items": { - "$ref": "#/definitions/txtType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of TXT records." - } - }, - "virtualNetworkLinks": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkLinkType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_roleAssignments": { - "copy": { - "name": "privateDnsZone_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_A": { - "copy": { - "name": "privateDnsZone_A", - "count": "[length(coalesce(parameters('a'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" - }, - "aRecords": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7372385900111002873" - }, - "name": "Private DNS Zone A record", - "description": "This module deploys a Private DNS Zone A record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the A record." - } - }, - "aRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" - }, - "description": "Optional. The list of A records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "A": { - "type": "Microsoft.Network/privateDnsZones/A", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aRecords": "[parameters('aRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "A_roleAssignments": { - "copy": { - "name": "A_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "A" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed A record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed A record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed A record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_AAAA": { - "copy": { - "name": "privateDnsZone_AAAA", - "count": "[length(coalesce(parameters('aaaa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" - }, - "aaaaRecords": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "14405855828972373002" - }, - "name": "Private DNS Zone AAAA record", - "description": "This module deploys a Private DNS Zone AAAA record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the AAAA record." - } - }, - "aaaaRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" - }, - "description": "Optional. The list of AAAA records in the record set." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "AAAA": { - "type": "Microsoft.Network/privateDnsZones/AAAA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aaaaRecords": "[parameters('aaaaRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "AAAA_roleAssignments": { - "copy": { - "name": "AAAA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "AAAA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AAAA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed AAAA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed AAAA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_CNAME": { - "copy": { - "name": "privateDnsZone_CNAME", - "count": "[length(coalesce(parameters('cname'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" - }, - "cnameRecord": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13818627461335065928" - }, - "name": "Private DNS Zone CNAME record", - "description": "This module deploys a Private DNS Zone CNAME record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the CNAME record." - } - }, - "cnameRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" - }, - "description": "Optional. A CNAME record." - }, - "nullable": true - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "CNAME": { - "type": "Microsoft.Network/privateDnsZones/CNAME", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "cnameRecord": "[parameters('cnameRecord')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "CNAME_roleAssignments": { - "copy": { - "name": "CNAME_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "CNAME" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed CNAME record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed CNAME record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed CNAME record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_MX": { - "copy": { - "name": "privateDnsZone_MX", - "count": "[length(coalesce(parameters('mx'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" - }, - "mxRecords": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "2977624679479439942" - }, - "name": "Private DNS Zone MX record", - "description": "This module deploys a Private DNS Zone MX record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the MX record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "mxRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" - }, - "description": "Optional. The list of MX records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "MX": { - "type": "Microsoft.Network/privateDnsZones/MX", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "mxRecords": "[parameters('mxRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "MX_roleAssignments": { - "copy": { - "name": "MX_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "MX" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed MX record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed MX record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed MX record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_PTR": { - "copy": { - "name": "privateDnsZone_PTR", - "count": "[length(coalesce(parameters('ptr'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" - }, - "ptrRecords": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "15286275176817336979" - }, - "name": "Private DNS Zone PTR record", - "description": "This module deploys a Private DNS Zone PTR record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the PTR record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ptrRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" - }, - "description": "Optional. The list of PTR records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "PTR": { - "type": "Microsoft.Network/privateDnsZones/PTR", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ptrRecords": "[parameters('ptrRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "PTR_roleAssignments": { - "copy": { - "name": "PTR_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "PTR" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed PTR record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed PTR record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed PTR record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SOA": { - "copy": { - "name": "privateDnsZone_SOA", - "count": "[length(coalesce(parameters('soa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" - }, - "soaRecord": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4837447718856535826" - }, - "name": "Private DNS Zone SOA record", - "description": "This module deploys a Private DNS Zone SOA record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SOA record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "soaRecord": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" - }, - "description": "Optional. A SOA record." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SOA": { - "type": "Microsoft.Network/privateDnsZones/SOA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "soaRecord": "[parameters('soaRecord')]", - "ttl": "[parameters('ttl')]" - } - }, - "SOA_roleAssignments": { - "copy": { - "name": "SOA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "SOA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SOA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SOA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SOA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SRV": { - "copy": { - "name": "privateDnsZone_SRV", - "count": "[length(coalesce(parameters('srv'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" - }, - "srvRecords": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "15028912535488490265" - }, - "name": "Private DNS Zone SRV record", - "description": "This module deploys a Private DNS Zone SRV record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SRV record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "srvRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" - }, - "description": "Optional. The list of SRV records in the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SRV": { - "type": "Microsoft.Network/privateDnsZones/SRV", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "srvRecords": "[parameters('srvRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "SRV_roleAssignments": { - "copy": { - "name": "SRV_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "SRV" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SRV record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SRV record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SRV record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_TXT": { - "copy": { - "name": "privateDnsZone_TXT", - "count": "[length(coalesce(parameters('txt'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" - }, - "txtRecords": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7641583415110009849" - }, - "name": "Private DNS Zone TXT record", - "description": "This module deploys a Private DNS Zone TXT record." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the TXT record." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." - }, - "nullable": true - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "txtRecords": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" - }, - "description": "Optional. The list of TXT records in the record set." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "TXT": { - "type": "Microsoft.Network/privateDnsZones/TXT", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]", - "txtRecords": "[parameters('txtRecords')]" - } - }, - "TXT_roleAssignments": { - "copy": { - "name": "TXT_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "TXT" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed TXT record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed TXT record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed TXT record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "resolutionPolicy": { - "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "7392770862892927923" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link." - }, - "parameters": { - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - }, - "resolutionPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - }, - "resolutionPolicy": "[parameters('resolutionPolicy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "logAnalyticsWorkspace": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "name": { - "value": "[variables('logAnalyticsWorkspaceResourceName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableReplication": { - "value": "[parameters('enableRedundancy')]" - }, - "replicationLocation": { - "value": "[variables('replicaLocation')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "9919485194443011422" - } - }, - "parameters": { - "solutionName": { - "type": "string", - "metadata": { - "description": "Solution name suffix used to derive the resource name." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('log-{0}', parameters('solutionName'))]", - "metadata": { - "description": "Optional. Override name for the Log Analytics workspace. Defaults to log-{solutionName}." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region for the resource." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resource." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": 365, - "metadata": { - "description": "Retention period in days. WAF recommends 365." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "metadata": { - "description": "SKU name for the workspace." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Public network access for ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Public network access for query." - } - }, - "enableReplication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable workspace replication for redundancy." - } - }, - "replicationLocation": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Replication location (paired region)." - } - }, - "dailyQuotaGb": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Daily quota in GB. WAF recommends 150 GB/day as starting point." - } - }, - "dataSources": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Data sources for VM monitoring (Windows events, perf counters)." - } - } - }, - "resources": { - "workspace": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.operational-insights.workspace.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "dataRetention": { - "value": "[parameters('retentionInDays')]" - }, - "skuName": { - "value": "[parameters('skuName')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "features": { - "value": { - "enableLogAccessUsingOnlyResourcePermissions": true - } - }, - "diagnosticSettings": { - "value": [ - { - "useThisWorkspace": true - } - ] - }, - "publicNetworkAccessForIngestion": { - "value": "[parameters('publicNetworkAccessForIngestion')]" - }, - "publicNetworkAccessForQuery": { - "value": "[parameters('publicNetworkAccessForQuery')]" - }, - "dailyQuotaGb": "[if(not(empty(parameters('dailyQuotaGb'))), createObject('value', parameters('dailyQuotaGb')), createObject('value', null()))]", - "replication": "[if(parameters('enableReplication'), createObject('value', createObject('enabled', true(), 'location', parameters('replicationLocation'))), createObject('value', null()))]", - "dataSources": "[if(not(empty(parameters('dataSources'))), createObject('value', parameters('dataSources')), createObject('value', null()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14099489006827800075" - }, - "name": "Log Analytics Workspaces", - "description": "This module deploys a Log Analytics Workspace." - }, - "definitions": { - "diagnosticSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "useThisWorkspace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "gallerySolutionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the gallery solutions to be created in the log analytics workspace." - } - }, - "storageInsightsConfigType": { - "type": "object", - "properties": { - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the storage account to be linked." - } - }, - "containers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of tables to be read by the workspace." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the storage insights configuration." - } - }, - "linkedServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the linked service. E.g., 'Automation' for an automation account, or 'Cluster' for a Log Analytics Cluster." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access (e.g., Automation Accounts)." - } - }, - "writeAccessResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access (e.g., Log Analytics Clusters)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked service." - } - }, - "linkedStorageAccountType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the link." - } - }, - "storageAccountIds": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked storage account." - } - }, - "savedSearchType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "etag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. The category of the saved search. This helps the user to find a saved search faster." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "functionAlias": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The function alias if query serves as a function." - } - }, - "functionParameters": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. The query expression for the saved search." - } - }, - "tags": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The tags attached to the saved search." - } - }, - "version": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The version number of the query language. The current version is 2 and is the default." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the saved search." - } - }, - "dataExportType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data export." - } - }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, - "metadata": { - "description": "Optional. The destination of the data export." - } - }, - "enable": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the data export." - } - }, - "tableNames": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of table names to export." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the data export." - } - }, - "dataSourceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "metadata": { - "description": "Required. The kind of data source." - } - }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the event log to configure when kind is WindowsEvent." - } - }, - "eventTypes": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "intervalSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." - } - }, - "syslogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." - } - }, - "syslogSeverities": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the data source." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "plan": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The plan for the table." - } - }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, - "metadata": { - "description": "Optional. The restored logs for the table." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. The schema for the table." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, - "metadata": { - "description": "Optional. The search results for the table." - } - }, - "retentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, - "metadata": { - "description": "Optional. The retention in days for the table. Don't provide to use the default workspace retention." - } - }, - "totalRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 2555, - "metadata": { - "description": "Optional. The total retention in days for the table. Don't provide use the default table retention." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The role assignments for the table." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the custom table." - } - }, - "workspaceFeaturesType": { - "type": "object", - "properties": { - "disableLocalAuth": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Disable Non-EntraID based Auth. Default is true." - } - }, - "enableDataExport": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag that indicate if data should be exported." - } - }, - "enableLogAccessUsingOnlyResourcePermissions": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable log access using only resource permissions. Default is false." - } - }, - "immediatePurgeDataOn30Days": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag that describes if we want to remove the data after 30 days." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Features of the workspace." - } - }, - "workspaceReplicationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether the replication is enabled or not. When true, workspace configuration and data is replicated to the specified location." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The location to which the workspace is replicated. Required if replication is enabled." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Replication properties of the workspace." - } - }, - "_1.columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], - "metadata": { - "description": "Required. The column type." - } - }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], - "nullable": true, - "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Column display name." - } - } - }, - "metadata": { - "description": "The parameters of the table column.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "destinationType": { - "type": "object", - "properties": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The destination resource ID." - } - }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination metadata." - } - } - }, - "metadata": { - "description": "The data export destination properties.", - "__bicep_imported_from!": { - "sourceTemplate": "data-export/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "restoredLogsType": { - "type": "object", - "properties": { - "sourceTable": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table to restore data from." - } - }, - "startRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." - } - }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the restore operation that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "description": "The table schema.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the search job that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Log Analytics workspace." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "allowedValues": [ - "CapacityReservation", - "Free", - "LACluster", - "PerGB2018", - "PerNode", - "Premium", - "Standalone", - "Standard" - ], - "metadata": { - "description": "Optional. The name of the SKU. Must be 'LACluster' to be linked to a Log Analytics cluster." - } - }, - "skuCapacityReservationLevel": { - "type": "int", - "defaultValue": 100, - "minValue": 100, - "maxValue": 5000, - "metadata": { - "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." - } - }, - "storageInsightsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/storageInsightsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of storage accounts to be read by the workspace." - } - }, - "linkedServices": { - "type": "array", - "items": { - "$ref": "#/definitions/linkedServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of services to be linked." - } - }, - "linkedStorageAccounts": { - "type": "array", - "items": { - "$ref": "#/definitions/linkedStorageAccountType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." - } - }, - "savedSearches": { - "type": "array", - "items": { - "$ref": "#/definitions/savedSearchType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Kusto Query Language searches to save." - } - }, - "dataExports": { - "type": "array", - "items": { - "$ref": "#/definitions/dataExportType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW data export instances to be deployed." - } - }, - "dataSources": { - "type": "array", - "items": { - "$ref": "#/definitions/dataSourceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW data sources to configure." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW custom tables to be deployed." - } - }, - "gallerySolutions": { - "type": "array", - "items": { - "$ref": "#/definitions/gallerySolutionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." - } - }, - "onboardWorkspaceToSentinel": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." - } - }, - "dataRetention": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 730, - "metadata": { - "description": "Optional. Number of days data will be retained for." - } - }, - "dailyQuotaGb": { - "type": "string", - "defaultValue": "-1", - "metadata": { - "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." - } - }, - "defaultDataCollectionRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the default Data Collection Rule to use for this workspace. Note: the default DCR is not applicable on workspace creation and the workspace must be listed as a destination in the DCR." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics query." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." - } - }, - "features": { - "$ref": "#/definitions/workspaceFeaturesType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace features." - } - }, - "replication": { - "$ref": "#/definitions/workspaceReplicationType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace replication properties." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "forceCmkForQuery": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether customer managed storage is mandatory for query management." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", - "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "features": { - "searchVersion": 1, - "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", - "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", - "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", - "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" - }, - "retentionInDays": "[parameters('dataRetention')]", - "workspaceCapping": { - "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" - }, - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "forceCmkForQuery": "[parameters('forceCmkForQuery')]", - "replication": "[parameters('replication')]", - "defaultDataCollectionRuleResourceId": "[parameters('defaultDataCollectionRuleResourceId')]" - }, - "identity": "[variables('identity')]" - }, - "logAnalyticsWorkspace_diagnosticSettings": { - "copy": { - "name": "logAnalyticsWorkspace_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_sentinelOnboarding": { - "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", - "type": "Microsoft.SecurityInsights/onboardingStates", - "apiVersion": "2025-09-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "default", - "properties": {}, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_roleAssignments": { - "copy": { - "name": "logAnalyticsWorkspace_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_storageInsightConfigs": { - "copy": { - "name": "logAnalyticsWorkspace_storageInsightConfigs", - "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "containers": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" - }, - "tables": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "140290971998938797" - }, - "name": "Log Analytics Workspace Storage Insight Configs", - "description": "This module deploys a Log Analytics Workspace Storage Insight Config." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the storage insights config." - } - }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource Manager ID of the storage account resource." - } - }, - "containers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The names of the Azure tables that the workspace should read." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" - }, - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "storageinsightconfig": { - "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "containers": "[parameters('containers')]", - "tables": "[parameters('tables')]", - "storageAccount": { - "id": "[parameters('storageAccountResourceId')]", - "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - } - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage insights configuration." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the storage insight configuration is deployed." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the storage insights configuration." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_linkedServices": { - "copy": { - "name": "logAnalyticsWorkspace_linkedServices", - "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" - }, - "resourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" - }, - "writeAccessResourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14482465616812596213" - }, - "name": "Log Analytics Workspace Linked Services", - "description": "This module deploys a Log Analytics Workspace Linked Service." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the link." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." - } - }, - "writeAccessResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "linkedService": { - "type": "Microsoft.OperationalInsights/workspaces/linkedServices", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resourceId": "[parameters('resourceId')]", - "writeAccessResourceId": "[parameters('writeAccessResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed linked service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed linked service." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the linked service is deployed." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_linkedStorageAccounts": { - "copy": { - "name": "logAnalyticsWorkspace_linkedStorageAccounts", - "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" - }, - "storageAccountIds": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "14864721709229272590" - }, - "name": "Log Analytics Workspace Linked Storage Accounts", - "description": "This module deploys a Log Analytics Workspace Linked Storage Account." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "allowedValues": [ - "Query", - "Alerts", - "CustomLogs", - "AzureWatson" - ], - "metadata": { - "description": "Required. Name of the link." - } - }, - "storageAccountIds": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "linkedStorageAccount": { - "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "properties": { - "storageAccountIds": "[parameters('storageAccountIds')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed linked storage account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed linked storage account." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the linked storage account is deployed." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_savedSearches": { - "copy": { - "name": "logAnalyticsWorkspace_savedSearches", - "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(subscription().id, resourceGroup().id))]" - }, - "etag": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" - }, - "displayName": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" - }, - "category": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" - }, - "query": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" - }, - "functionAlias": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" - }, - "functionParameters": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" - }, - "tags": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" - }, - "version": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17904092372918022238" - }, - "name": "Log Analytics Workspace Saved Searches", - "description": "This module deploys a Log Analytics Workspace Saved Search." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. Query category." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. Kusto Query to be stored." - } - }, - "tags": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - }, - "functionAlias": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The function alias if query serves as a function." - } - }, - "functionParameters": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "version": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The version number of the query language." - } - }, - "etag": { - "type": "string", - "defaultValue": "*", - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "savedSearch": { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "properties": { - "etag": "[parameters('etag')]", - "tags": "[coalesce(parameters('tags'), createArray())]", - "displayName": "[parameters('displayName')]", - "category": "[parameters('category')]", - "query": "[parameters('query')]", - "functionAlias": "[parameters('functionAlias')]", - "functionParameters": "[parameters('functionParameters')]", - "version": "[parameters('version')]" - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed saved search." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the saved search is deployed." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed saved search." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "logAnalyticsWorkspace_linkedStorageAccounts" - ] - }, - "logAnalyticsWorkspace_dataExports": { - "copy": { - "name": "logAnalyticsWorkspace_dataExports", - "count": "[length(coalesce(parameters('dataExports'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "workspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" - }, - "destination": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" - }, - "enable": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" - }, - "tableNames": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17943947755417749524" - }, - "name": "Log Analytics Workspace Data Exports", - "description": "This module deploys a Log Analytics Workspace Data Export." - }, - "definitions": { - "destinationType": { - "type": "object", - "properties": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The destination resource ID." - } - }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination metadata." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The data export destination properties." - } - } - }, - "parameters": { - "name": { - "type": "string", - "minLength": 4, - "maxLength": 63, - "metadata": { - "description": "Required. The data export rule name." - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." - } - }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, - "metadata": { - "description": "Optional. Destination properties." - } - }, - "enable": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Active when enabled." - } - }, - "tableNames": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" - }, - "dataExport": { - "type": "Microsoft.OperationalInsights/workspaces/dataExports", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", - "properties": { - "destination": "[parameters('destination')]", - "enable": "[parameters('enable')]", - "tableNames": "[parameters('tableNames')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the data export." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the data export." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the data export was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_dataSources": { - "copy": { - "name": "logAnalyticsWorkspace_dataSources", - "count": "[length(coalesce(parameters('dataSources'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" - }, - "kind": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" - }, - "linkedResourceId": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" - }, - "eventLogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" - }, - "eventTypes": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" - }, - "objectName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" - }, - "instanceName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" - }, - "intervalSeconds": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" - }, - "counterName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" - }, - "state": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" - }, - "syslogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" - }, - "syslogSeverities": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" - }, - "performanceCounters": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" - }, - "tags": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "15360290236166491819" - }, - "name": "Log Analytics Workspace Datasources", - "description": "This module deploys a Log Analytics Workspace Data Source." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "defaultValue": "AzureActivityLog", - "allowedValues": [ - "AzureActivityLog", - "WindowsEvent", - "WindowsPerformanceCounter", - "IISLogs", - "LinuxSyslog", - "LinuxSyslogCollection", - "LinuxPerformanceObject", - "LinuxPerformanceCollection" - ], - "metadata": { - "description": "Optional. The kind of the data source." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" - }, - "description": "Optional. Tags to configure in the resource." - }, - "nullable": true - }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the resource to be linked." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Windows event log name to configure when kind is WindowsEvent." - } - }, - "eventTypes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Windows event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "defaultValue": "*", - "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "intervalSeconds": { - "type": "int", - "defaultValue": 60, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." - } - }, - "syslogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." - } - }, - "syslogSeverities": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "dataSource": { - "type": "Microsoft.OperationalInsights/workspaces/dataSources", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "kind": "[parameters('kind')]", - "tags": "[parameters('tags')]", - "properties": { - "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", - "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", - "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", - "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", - "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", - "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", - "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", - "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", - "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", - "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", - "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed data source." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the data source is deployed." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed data source." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_tables": { - "copy": { - "name": "logAnalyticsWorkspace_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Table-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "workspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "plan": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" - }, - "schema": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" - }, - "retentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" - }, - "totalRetentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" - }, - "restoredLogs": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" - }, - "searchResults": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "18383178824663161801" - }, - "name": "Log Analytics Workspace Tables", - "description": "This module deploys a Log Analytics Workspace Table." - }, - "definitions": { - "restoredLogsType": { - "type": "object", - "properties": { - "sourceTable": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table to restore data from." - } - }, - "startRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." - } - }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the restore operation that initiated the table." - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The table schema." - } - }, - "columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], - "metadata": { - "description": "Required. The column type." - } - }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], - "nullable": true, - "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Column display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the table column." - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the search job that initiated the table." - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." - } - }, - "plan": { - "type": "string", - "defaultValue": "Analytics", - "allowedValues": [ - "Basic", - "Analytics" - ], - "metadata": { - "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." - } - }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, - "metadata": { - "description": "Optional. Restore parameters." - } - }, - "retentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 730, - "metadata": { - "description": "Optional. The table retention in days, between 4 and 730. Don't provide to use the default workspace retention." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. Table's schema." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, - "metadata": { - "description": "Optional. Parameters of the search job that initiated this table." - } - }, - "totalRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 4, - "maxValue": 2555, - "metadata": { - "description": "Optional. The table total retention in days, between 4 and 2555. Don't provide use the default table retention." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-07-01", - "name": "[parameters('workspaceName')]" - }, - "table": { - "type": "Microsoft.OperationalInsights/workspaces/tables", - "apiVersion": "2025-07-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", - "properties": { - "plan": "[parameters('plan')]", - "restoredLogs": "[parameters('restoredLogs')]", - "retentionInDays": "[coalesce(parameters('retentionInDays'), -1)]", - "schema": "[parameters('schema')]", - "searchResults": "[parameters('searchResults')]", - "totalRetentionInDays": "[coalesce(parameters('totalRetentionInDays'), -1)]" - } - }, - "table_roleAssignments": { - "copy": { - "name": "table_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "table" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_solutions": { - "copy": { - "name": "logAnalyticsWorkspace_solutions", - "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" - }, - "condition": "[not(empty(parameters('gallerySolutions')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-LAW-Solution-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "plan": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "10255889523646649592" - }, - "name": "Operations Management Solutions", - "description": "This module deploys an Operations Management Solution.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - }, - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2021-06-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "solution": { - "type": "Microsoft.OperationsManagement/solutions", - "apiVersion": "2015-11-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" - }, - "plan": { - "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", - "promotionCode": "", - "product": "[parameters('plan').product]", - "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed solution." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed solution." - }, - "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the solution is deployed." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('solution', '2015-11-01-preview', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed log analytics workspace." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed log analytics workspace." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed log analytics workspace." - }, - "value": "[parameters('name')]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "The ID associated with the workspace." - }, - "value": "[reference('logAnalyticsWorkspace').customerId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('logAnalyticsWorkspace', '2025-07-01', 'full').location]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2025-07-01', 'full'), 'identity'), 'principalId')]" - }, - "primarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The primary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').primarySharedKey]" - }, - "secondarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The secondary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2025-07-01').secondarySharedKey]" - } - } - } - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the Log Analytics workspace." - }, - "value": "[reference('workspace').outputs.resourceId.value]" - }, - "name": { - "type": "string", - "metadata": { - "description": "Name of the Log Analytics workspace." - }, - "value": "[reference('workspace').outputs.name.value]" - }, - "location": { - "type": "string", - "metadata": { - "description": "Location of the workspace." - }, - "value": "[parameters('location')]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "Log Analytics workspace customer ID." - }, - "value": "[reference('workspace').outputs.logAnalyticsWorkspaceId.value]" - } - } - } - } - }, - "applicationInsights": { - "condition": "[parameters('enableMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.insights.component.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appi-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "retentionInDays": { - "value": 365 - }, - "kind": { - "value": "web" - }, - "disableIpMasking": { - "value": false - }, - "flowType": { - "value": "Bluefield" - }, - "workspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value), createObject('value', ''))]", - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17358780145253914698" - }, - "name": "Application Insights", - "description": "This component deploys an Application Insights instance." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application Insights." - } - }, - "applicationType": { - "type": "string", - "defaultValue": "web", - "allowedValues": [ - "web", - "other" - ], - "metadata": { - "description": "Optional. Application type." - } - }, - "workspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." - } - }, - "disableIpMasking": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable IP masking. Default value is set to true." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." - } - }, - "forceCustomerStorageForProfiler": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Force users to create their own storage account for profiler and debugger." - } - }, - "linkedStorageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Linked storage account resource ID." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": 365, - "allowedValues": [ - 30, - 60, - 90, - 120, - 180, - 270, - 365, - 550, - 730 - ], - "metadata": { - "description": "Optional. Retention period in days." - } - }, - "samplingPercentage": { - "type": "int", - "defaultValue": 100, - "minValue": 0, - "maxValue": 100, - "metadata": { - "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." - } - }, - "flowType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." - } - }, - "requestSource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." - } - }, - "kind": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." - } - }, - "immediatePurgeDataOn30Days": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Purge data immediately after 30 days." - } - }, - "ingestionMode": { - "type": "string", - "nullable": true, - "allowedValues": [ - "ApplicationInsights", - "ApplicationInsightsWithDiagnosticSettings", - "LogAnalytics" - ], - "metadata": { - "description": "Optional. Indicates the flow of the ingestion." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Insights/components@2020-02-02#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", - "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", - "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "appInsights": { - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "Application_Type": "[parameters('applicationType')]", - "DisableIpMasking": "[parameters('disableIpMasking')]", - "DisableLocalAuth": "[parameters('disableLocalAuth')]", - "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", - "WorkspaceResourceId": "[parameters('workspaceResourceId')]", - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "RetentionInDays": "[parameters('retentionInDays')]", - "SamplingPercentage": "[parameters('samplingPercentage')]", - "Flow_Type": "[parameters('flowType')]", - "Request_Source": "[parameters('requestSource')]", - "ImmediatePurgeDataOn30Days": "[parameters('immediatePurgeDataOn30Days')]", - "IngestionMode": "[parameters('ingestionMode')]" - } - }, - "appInsights_roleAssignments": { - "copy": { - "name": "appInsights_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_diagnosticSettings": { - "copy": { - "name": "appInsights_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "linkedStorageAccount": { - "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appInsightsName": { - "value": "[parameters('name')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "5059808225314360251" - }, - "name": "Application Insights Linked Storage Account", - "description": "This component deploys an Application Insights Linked Storage Account." - }, - "parameters": { - "appInsightsName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." - } - }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Linked storage account resource ID." - } - } - }, - "resources": [ - { - "type": "microsoft.insights/components/linkedStorageAccounts", - "apiVersion": "2020-03-01-preview", - "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", - "properties": { - "linkedStorageAccount": "[parameters('storageAccountResourceId')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Linked Storage Account." - }, - "value": "ServiceProfiler" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Linked Storage Account." - }, - "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the agent pool was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "appInsights" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the application insights component." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application insights component." - }, - "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the application insights component was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "applicationId": { - "type": "string", - "metadata": { - "description": "The application ID of the application insights component." - }, - "value": "[reference('appInsights').AppId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('appInsights', '2020-02-02', 'full').location]" - }, - "instrumentationKey": { - "type": "string", - "metadata": { - "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." - }, - "value": "[reference('appInsights').InstrumentationKey]" - }, - "connectionString": { - "type": "string", - "metadata": { - "description": "Application Insights Connection String." - }, - "value": "[reference('appInsights').ConnectionString]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "avmManagedIdentity": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "identityName": { - "value": "[format('id-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "5270291310649425810" - } - }, - "parameters": { - "solutionName": { - "type": "string", - "metadata": { - "description": "Solution name used for resource naming." - } - }, - "identityName": { - "type": "string", - "defaultValue": "[format('id-{0}', parameters('solutionName'))]", - "metadata": { - "description": "Name of the managed identity." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region for the resource." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('identityName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." - }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "isolationScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], - "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" - }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" - }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" - }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "1387931959101373036" - }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." - }, - "parameters": { - "userAssignedIdentityName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "audiences": { - "type": "array", - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." - } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the federated identity credential." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the federated identity credential." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the federated identity credential was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "userAssignedIdentity" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Principal ID of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "Client ID of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" - }, - "name": { - "type": "string", - "metadata": { - "description": "Name of the managed identity." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" - } - } - } - } - }, - "avmContainerRegistry": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "name": { - "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "acrPullPrincipalIds": { - "value": [ - "[reference('avmContainerRegistryReader').outputs.principalId.value]" - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enablePrivateNetworking": { - "value": "[parameters('enablePrivateNetworking')]" - }, - "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.backendSubnetResourceId.value), createObject('value', ''))]", - "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)).outputs.resourceId.value)), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8138805991948000285" - } - }, - "parameters": { - "solutionName": { - "type": "string", - "metadata": { - "description": "Solution name used for naming convention." - } - }, - "name": { - "type": "string", - "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", - "metadata": { - "description": "Name of the container registry." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Azure region for deployment." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Resource tags." - } - }, - "sku": { - "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Standard", - "Premium" - ], - "metadata": { - "description": "SKU for the container registry." - } - }, - "adminUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable admin user for the registry." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Public network access setting." - } - }, - "exportPolicyStatus": { - "type": "string", - "defaultValue": "enabled", - "metadata": { - "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." - } - }, - "acrPullPrincipalIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Principal IDs to assign AcrPull role." - } - }, - "enablePrivateNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable private networking." - } - }, - "privateEndpointSubnetId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Subnet resource ID for private endpoint." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Private DNS zone resource IDs for private endpoint." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable Azure telemetry collection." - } - } - }, - "variables": { - "copy": [ - { - "name": "roleAssignments", - "count": "[length(parameters('acrPullPrincipalIds'))]", - "input": { - "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", - "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", - "principalType": "ServicePrincipal" - } - }, - { - "name": "dnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneResourceIds'))]", - "input": { - "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", - "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" - } - } - ], - "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", - "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "acrSku": { - "value": "[parameters('sku')]" - }, - "acrAdminUserEnabled": { - "value": "[parameters('adminUserEnabled')]" - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - }, - "exportPolicyStatus": { - "value": "[parameters('exportPolicyStatus')]" - }, - "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", - "privateEndpoints": { - "value": "[variables('privateEndpointConfig')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1509121545318808417" - }, - "name": "Azure Container Registries (ACR)", - "description": "This module deploys an Azure Container Registry (ACR)." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "credentialSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" - }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a credential set." - } - }, - "scopeMapsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the scope map." - } - }, - "actions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" - }, - "description": "Required. The list of scoped permissions for registry artifacts." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The user friendly description of the scope map." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a scope map." - } - }, - "cacheRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cache rule." - } - }, - "replicationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } - }, - "zoneRedundancy": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" - }, - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replication." - } - }, - "taskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the task." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" - }, - "description": "Optional. The platform properties for the task." - }, - "nullable": true - }, - "step": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" - }, - "description": "Optional. The step properties for the task." - }, - "nullable": true - }, - "trigger": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" - }, - "description": "Optional. The trigger properties for the task." - }, - "nullable": true - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" - }, - "description": "Optional. The status of the task at the time the operation was called." - }, - "nullable": true - }, - "timeout": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." - } - }, - "agentConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" - }, - "description": "Optional. The agent configuration for the task." - }, - "nullable": true - }, - "agentPoolName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." - } - }, - "isSystemTask": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." - } - }, - "logTemplate": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The log template for the task to use when creating logs in Log Analytics." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a task." - } - }, - "tokenType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the token." - } - }, - "scopeMapResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the scope map which defines the permissions for this token." - } - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" - }, - "description": "Optional. The status of the token at the time the operation was called." - }, - "nullable": true - }, - "credentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." - } - } - } - }, - "webhookType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "string", - "metadata": { - "description": "Required. The service URI for the webhook to post notifications." - } - }, - "status": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" - }, - "description": "Optional. The status of the webhook at the time the operation was called." - }, - "nullable": true - }, - "action": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "customHeaders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" - }, - "description": "Optional. Custom headers that will be added to the webhook notifications." - }, - "nullable": true - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a webhook." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "authCredentialsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } - }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." - } - }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } - }, - "metadata": { - "description": "The type for auth credentials.", - "__bicep_imported_from!": { - "sourceTemplate": "credential-set/main.bicep" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityOnlySysAssignedType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. Name of your Azure Container Registry." - } - }, - "acrAdminUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable admin user that have push / pull permission to the registry." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "autoGeneratedDomainNameLabelScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse", - "Unsecure" - ], - "metadata": { - "description": "Optional. The domain name label reuse scope." - } - }, - "roleAssignmentMode": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AbacRepositoryPermissions", - "LegacyRegistryPermissions" - ], - "metadata": { - "description": "Optional. The registry permissions role assignment mode." - } - }, - "acrSku": { - "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Premium", - "Standard" - ], - "metadata": { - "description": "Optional. Tier of your Azure container registry." - } - }, - "exportPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the export policy is enabled or not." - } - }, - "quarantinePolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "trustPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "retentionPolicyStatus": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the retention policy is enabled or not." - } - }, - "retentionPolicyDays": { - "type": "int", - "defaultValue": 15, - "metadata": { - "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." - } - }, - "azureADAuthenticationAsArmPolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." - } - }, - "softDeletePolicyStatus": { - "type": "string", - "defaultValue": "disabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. Soft Delete policy status. Default is disabled." - } - }, - "softDeletePolicyDays": { - "type": "int", - "defaultValue": 7, - "metadata": { - "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." - } - }, - "dataEndpointEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "networkRuleBypassOptions": { - "type": "string", - "defaultValue": "AzureServices", - "allowedValues": [ - "AzureServices", - "None" - ], - "metadata": { - "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." - } - }, - "networkRuleSetDefaultAction": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Optional. The default action of allow or deny when no other rules match." - } - }, - "networkRuleSetIpRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." - } - }, - "zoneRedundancy": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } - }, - "replications": { - "type": "array", - "items": { - "$ref": "#/definitions/replicationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All replications to create." - } - }, - "webhooks": { - "type": "array", - "items": { - "$ref": "#/definitions/webhookType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All webhooks to create." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." - } - }, - "anonymousPullEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "cacheRules": { - "type": "array", - "items": { - "$ref": "#/definitions/cacheRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Cache Rules." - } - }, - "credentialSets": { - "type": "array", - "items": { - "$ref": "#/definitions/credentialSetType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Credential Sets." - } - }, - "scopeMaps": { - "type": "array", - "items": { - "$ref": "#/definitions/scopeMapsType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Scope maps setting." - } - }, - "tokens": { - "type": "array", - "items": { - "$ref": "#/definitions/tokenType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tokens to create for the container registry." - } - }, - "tasks": { - "type": "array", - "items": { - "$ref": "#/definitions/taskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of ACR Tasks to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", - "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", - "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", - "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", - "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", - "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", - "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", - "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", - "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", - "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", - "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "registry": { - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-06-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('acrSku')]" - }, - "properties": { - "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", - "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", - "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", - "roleAssignmentMode": "[parameters('roleAssignmentMode')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", - "policies": { - "azureADAuthenticationAsArmPolicy": { - "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" - }, - "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", - "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", - "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", - "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", - "softDeletePolicy": { - "retentionDays": "[parameters('softDeletePolicyDays')]", - "status": "[parameters('softDeletePolicyStatus')]" - } - }, - "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", - "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", - "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", - "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", - "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "registry_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_diagnosticSettings": { - "copy": { - "name": "registry_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_roleAssignments": { - "copy": { - "name": "registry_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "registry" - ] - }, - "registry_scopeMaps": { - "copy": { - "name": "registry_scopeMaps", - "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" - }, - "actions": { - "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3787322352564227867" - }, - "name": "Container Registries scope maps", - "description": "This module deploys an Azure Container Registry (ACR) scope map." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", - "metadata": { - "description": "Optional. The name of the scope map." - } - }, - "actions": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of scoped permissions for registry artifacts." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The user friendly description of the scope map." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "scopeMap": { - "type": "Microsoft.ContainerRegistry/registries/scopeMaps", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "actions": "[parameters('actions')]", - "description": "[parameters('description')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the scope map." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the scope map was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the scope map." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_replications": { - "copy": { - "name": "registry_replications", - "count": "[length(coalesce(parameters('replications'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" - }, - "regionEndpointEnabled": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" - }, - "zoneRedundancy": { - "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "6219097750044645017" - }, - "name": "Azure Container Registry (ACR) Replications", - "description": "This module deploys an Azure Container Registry (ACR) Replication." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the replication." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "regionEndpointEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." - } - }, - "zoneRedundancy": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Whether or not zone redundancy is enabled for this container registry." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "replication": { - "type": "Microsoft.ContainerRegistry/registries/replications", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", - "zoneRedundancy": "[parameters('zoneRedundancy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the replication." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the replication." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the replication was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('replication', '2025-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_credentialSets": { - "copy": { - "name": "registry_credentialSets", - "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "managedIdentities": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" - }, - "authCredentials": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" - }, - "loginServer": { - "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13412699468141336519" - }, - "name": "Container Registries Credential Sets", - "description": "This module deploys an ACR Credential Set." - }, - "definitions": { - "authCredentialsType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential." - } - }, - "usernameSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the username." - } - }, - "passwordSecretIdentifier": { - "type": "string", - "metadata": { - "description": "Required. KeyVault Secret URI for accessing the password." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for auth credentials." - } - }, - "managedIdentityOnlySysAssignedType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the credential set." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlySysAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "authCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/authCredentialsType" - }, - "metadata": { - "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." - } - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "Required. The credentials are stored for this upstream or login server." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "credentialSet": { - "type": "Microsoft.ContainerRegistry/registries/credentialSets", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", - "properties": { - "authCredentials": "[parameters('authCredentials')]", - "loginServer": "[parameters('loginServer')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Credential Set." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Credential Set." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Credential Set." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" - } - } - } - }, - "dependsOn": [ - "registry" - ] - }, - "registry_cacheRules": { - "copy": { - "name": "registry_cacheRules", - "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "registryName": { - "value": "[parameters('name')]" - }, - "sourceRepository": { - "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" - }, - "targetRepository": { - "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" - }, - "credentialSetResourceId": { - "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1319901650921923538" - }, - "name": "Container Registry Cache", - "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", - "metadata": { - "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." - } - }, - "sourceRepository": { - "type": "string", - "metadata": { - "description": "Required. Source repository pulled from upstream." - } - }, - "targetRepository": { - "type": "string", - "defaultValue": "[parameters('sourceRepository')]", - "metadata": { - "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." - } - }, - "credentialSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "cacheRule": { - "type": "Microsoft.ContainerRegistry/registries/cacheRules", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "sourceRepository": "[parameters('sourceRepository')]", - "targetRepository": "[parameters('targetRepository')]", - "credentialSetResourceId": "[parameters('credentialSetResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Cache Rule." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Cache Rule." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cache Rule." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry", - "registry_credentialSets" - ] - }, - "registry_tokens": { - "copy": { - "name": "registry_tokens", - "count": "[length(coalesce(parameters('tokens'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "scopeMapResourceId": { - "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" - }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "5970335582661416899" - }, - "name": "Container Registries Tokens", - "description": "Deploys an Azure Container Registry (ACR) Token." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. The name of the token." - } - }, - "scopeMapResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the scope map to which the token will be associated with." - } - }, - "status": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The status of the token. Default is enabled." - } - }, - "credentials": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" - }, - "description": "Optional. The credentials associated with the token for authentication." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "token": { - "type": "Microsoft.ContainerRegistry/registries/tokens", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "properties": { - "scopeMapId": "[parameters('scopeMapResourceId')]", - "status": "[parameters('status')]", - "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the token." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the token was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the token." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "registry", - "registry_scopeMaps" - ] - }, - "registry_tasks": { - "copy": { - "name": "registry_tasks", - "count": "[length(coalesce(parameters('tasks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "registryName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "platform": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" - }, - "step": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" - }, - "trigger": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" - }, - "timeout": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" - }, - "agentConfiguration": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" - }, - "agentPoolName": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" - }, - "credentials": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" - }, - "isSystemTask": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" - }, - "logTemplate": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" - }, - "managedIdentities": { - "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2468771835002458415" - }, - "name": "Container Registries Tasks", - "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." - }, - "definitions": { - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Required. The name of the task." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" - }, - "description": "Optional. The platform properties against which the task has to run." - }, - "nullable": true - }, - "step": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" - }, - "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." - }, - "nullable": true - }, - "trigger": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" - }, - "description": "Optional. The properties that describe all triggers for the task." - }, - "nullable": true - }, - "status": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. The current status of task." - } - }, - "timeout": { - "type": "int", - "defaultValue": 3600, - "minValue": 300, - "maxValue": 28800, - "metadata": { - "description": "Optional. Run timeout in seconds." - } - }, - "agentConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" - }, - "description": "Optional. The machine configuration of the run agent." - }, - "nullable": true - }, - "agentPoolName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The dedicated agent pool for the task." - } - }, - "credentials": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" - }, - "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." - }, - "nullable": true - }, - "isSystemTask": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The value of this property indicates whether the task resource is system task or not." - } - }, - "logTemplate": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The template that describes the repository and tag information for run log artifact." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "task": { - "type": "Microsoft.ContainerRegistry/registries/tasks", - "apiVersion": "2025-03-01-preview", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": { - "agentConfiguration": "[parameters('agentConfiguration')]", - "agentPoolName": "[parameters('agentPoolName')]", - "credentials": "[parameters('credentials')]", - "isSystemTask": "[parameters('isSystemTask')]", - "logTemplate": "[parameters('logTemplate')]", - "platform": "[parameters('platform')]", - "status": "[parameters('status')]", - "step": "[parameters('step')]", - "timeout": "[parameters('timeout')]", - "trigger": "[parameters('trigger')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the task." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the task was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the task." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('task', '2025-03-01-preview', 'full').location]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" - } + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, - "dependsOn": [ - "registry" - ] + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } }, - "registry_webhooks": { - "copy": { - "name": "registry_webhooks", - "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" - }, - "registryName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "action": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" - }, - "customHeaders": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" - }, - "status": { - "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" - }, - "serviceUri": { - "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "principalId": { + "type": "string", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3200175097987099858" - }, - "name": "Azure Container Registry (ACR) Webhooks", - "description": "This module deploys an Azure Container Registry (ACR) Webhook." - }, - "parameters": { - "registryName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}webhook', parameters('registryName'))]", - "minLength": 5, - "maxLength": 50, - "metadata": { - "description": "Optional. The name of the registry webhook." - } - }, - "serviceUri": { - "type": "securestring", - "metadata": { - "description": "Required. The service URI for the webhook to post notifications." - } - }, - "status": { - "type": "string", - "defaultValue": "enabled", - "allowedValues": [ - "disabled", - "enabled" - ], - "metadata": { - "description": "Optional. The status of the webhook at the time the operation was called." - } - }, - "action": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [ - "chart_delete", - "chart_push", - "delete", - "push", - "quarantine" - ], - "metadata": { - "description": "Optional. The list of actions that trigger the webhook to post notifications." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "customHeaders": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Custom headers that will be added to the webhook notifications." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes OR the resource ID of the IPAM pool to be used for the Virtual Network. When specifying an IPAM pool resource ID you must also set a value for the parameter called `ipamPoolNumberOfIpAddresses`." + } + }, + "ipamPoolNumberOfIpAddresses": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Number of IP addresses allocated from the pool. To be used only when the addressPrefix param is defined with a resource ID of an IPAM pool." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + }, + "enablePrivateEndpointVNetPolicies": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Basic", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables high scale private endpoints for the virtual network. This is necessary if the virtual network requires more than 1000 private endpoints or is peered to virtual networks with a total of more than 4000 private endpoints." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "registry": { - "existing": true, - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-11-01", - "name": "[parameters('registryName')]" - }, - "webhook": { - "type": "Microsoft.ContainerRegistry/registries/webhooks", - "apiVersion": "2025-11-01", - "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "actions": "[parameters('action')]", - "customHeaders": "[parameters('customHeaders')]", - "scope": "[parameters('scope')]", - "serviceUri": "[parameters('serviceUri')]", - "status": "[parameters('status')]" - } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": "[if(contains(parameters('addressPrefixes')[0], '/Microsoft.Network/networkManagers/'), createObject('ipamPoolPrefixAllocations', createArray(createObject('pool', createObject('id', parameters('addressPrefixes')[0]), 'numberOfIpAddresses', parameters('ipamPoolNumberOfIpAddresses')))), createObject('addressPrefixes', parameters('addressPrefixes')))]", + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]", + "privateEndpointVNetPolicies": "[parameters('enablePrivateEndpointVNetPolicies')]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the webhook." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the webhook." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Azure container registry." - }, - "value": "[resourceGroup().name]" - }, - "actions": { - "type": "array", - "metadata": { - "description": "The actions of the webhook." - }, - "value": "[reference('webhook').actions]" - }, - "status": { - "type": "string", - "metadata": { - "description": "The status of the webhook." - }, - "value": "[reference('webhook').status]" - }, - "provistioningState": { - "type": "string", - "metadata": { - "description": "The provisioning state of the webhook." - }, - "value": "[reference('webhook').provisioningState]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('webhook', '2025-11-01', 'full').location]" + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } - } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "registry" + "virtualNetwork" ] }, - "registry_privateEndpoints": { + "virtualNetwork_roleAssignments": { "copy": { - "name": "registry_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[format('{0}-subnet-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "ipamPoolPrefixAllocations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'ipamPoolPrefixAllocations')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -27402,98 +8348,12 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "18436885663402767850" + "templateHash": "13992200806189615656" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." }, "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, "roleAssignmentType": { "type": "object", "properties": { @@ -27565,7 +8425,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" } } } @@ -27574,71 +8434,134 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. The Name of the subnet resource." } }, - "subnetResourceId": { + "virtualNetworkName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." } }, - "applicationSecurityGroupResourceIds": { + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "ipamPoolPrefixAllocations": { "type": "array", "items": { - "type": "string" + "type": "object" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Conditional. The address space for the subnet, deployed from IPAM Pool. Required if `addressPrefixes` and `addressPrefix` is empty." } }, - "customNetworkInterfaceName": { + "networkSecurityGroupResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. The resource ID of the network security group to assign to the subnet." } }, - "ipConfigurations": { - "type": "array", + "routeTableResourceId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" }, - "nullable": true + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } }, - "ipVersionType": { + "delegation": { "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" }, - "defaultValue": "IPv4" + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", + "defaultOutboundAccess": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." } }, - "location": { + "sharingScope": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Application gateway IP configurations of virtual network resource." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. An array of service endpoint policies." } }, "roleAssignments": { @@ -27651,46 +8574,6 @@ "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, "enableTelemetry": { "type": "bool", "defaultValue": true, @@ -27709,23 +8592,19 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -27741,56 +8620,50 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", "properties": { "copy": [ { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" } } ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "ipamPoolPrefixAllocations": "[parameters('ipamPoolPrefixAllocations')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" } }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { + "subnet_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "subnet_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -27801,2925 +8674,2620 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" + "subnet" ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + }, + "ipamPoolPrefixAllocations": { + "type": "array", + "metadata": { + "description": "The IPAM pool prefix allocations for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'ipamPoolPrefixAllocations'), createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." }, - "dependsOn": [ - "privateEndpoint" - ] + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "6939030350004475953" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." }, - "outputs": { - "resourceGroupName": { + "parameters": { + "name": { "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } }, - "resourceId": { + "localVnetName": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } }, - "name": { + "remoteVirtualNetworkResourceId": { "type": "string", "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } }, - "location": { + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The resource group the virtual network peering was deployed into." }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + "value": "[resourceGroup().name]" }, - "customDnsConfigs": { - "type": "array", + "name": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." + "description": "The name of the virtual network peering." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[parameters('name')]" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "resourceId": { + "type": "string", "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The resource ID of the virtual network peering." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-05-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "nsgs" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.name.value]" + }, + "resourceId": { + "type": "string", + "value": "[reference('virtualNetwork').outputs.resourceId.value]" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetOutputType" + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex()].name]", + "resourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[copyIndex()]]", + "nsgName": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), null())]", + "nsgResourceId": "[if(not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup'))), reference(format('nsgs[{0}]', copyIndex())).outputs.resourceId.value, null())]" + } + } + }, + "backendSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'backend')], '')]" + }, + "webserverfarmSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'webserverfarm')], '')]" + }, + "administrationSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'administration')], '')]" + }, + "bastionSubnetResourceId": { + "type": "string", + "value": "[if(contains(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet'), reference('virtualNetwork').outputs.subnetResourceIds.value[indexOf(map(parameters('subnets'), lambda('subnet', lambdaVariables('subnet').name)), 'AzureBastionSubnet')], '')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.bastion-host.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('bastionHostName')]" + }, + "skuName": { + "value": "Standard" + }, + "location": { + "value": "[parameters('location')]" + }, + "virtualNetworkResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('name', 'bastionDiagnostics', 'workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value, 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": { + "name": "[format('pip-{0}', variables('bastionHostName'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9712719642210419114" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the Bastion host." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "metadata": { + "description": "SKU name for the Bastion host." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the virtual network hosting the AzureBastionSubnet." + } + }, + "diagnosticSettings": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings to apply to the Bastion host." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "publicIPAddressObject": { + "type": "object", + "metadata": { + "description": "Public IP configuration object for the Bastion host." + } + } + }, + "resources": { + "bastionHost": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.bastion-host.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "[parameters('skuName')]" + }, + "virtualNetworkResourceId": { + "value": "[parameters('virtualNetworkResourceId')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": "[parameters('publicIPAddressObject')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7741601918225805390" + }, + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host." + }, + "definitions": { + "publicIPAddressObjectType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for the Public IP resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create for the Public IP resource." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the Public IP module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Idle timeout in minutes for the Public IP resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" }, - "groupId": { + "description": "Optional. Tags to apply to the Public IP resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the Public IP resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." } } }, - "dependsOn": [ - "registry", - "registry_replications" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The Name of the Azure container registry." - }, - "value": "[parameters('name')]" - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "The reference to the Azure container registry." - }, - "value": "[reference('registry').loginServer]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Azure container registry." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Azure container registry." - }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" + } + } }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, - "value": "[reference('registry', '2025-06-01-preview', 'full').location]" - }, - "credentialSetsSystemAssignedMIPrincipalIds": { - "type": "array", "metadata": { - "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "credentialSetsResourceIds": { - "type": "array", - "metadata": { - "description": "The Resource IDs of the ACR Credential Sets." + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", - "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } }, "metadata": { - "description": "The private endpoints of the Azure container registry." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" } } - } - } - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container registry." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "The login server URL." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container registry." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" - } - } - } - }, - "dependsOn": [ - "avmContainerRegistryReader", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').containerRegistry)]", - "virtualNetwork" - ] - }, - "avmStorageAccount": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "minimumTlsVersion": { - "value": "TLS1_2" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_API').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - }, - { - "roleDefinitionIdOrName": "Storage Queue Data Contributor", - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", - "ipRules": [] - } - }, - "requireInfrastructureEncryption": { - "value": true - }, - "supportsHttpsTrafficOnly": { - "value": true - }, - "accessTier": { - "value": "Hot" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)).outputs.resourceId.value))), 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1254456195180100771" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.10.0" } } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoints output." - } - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network configuration." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey1 secret name to create." - } - }, - "connectionString1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString1 secret name to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The accessKey2 secret name to create." - } - }, - "connectionString2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The connectionString2 secret name to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the exported secrets." - } - }, - "localUserType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The local user home directory." - } - }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" - }, - "metadata": { - "description": "Required. The permission scopes of the local user." - } - }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a local user." - } - }, - "blobServiceType": { - "type": "object", - "properties": { - "automaticSnapshotPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." - } - }, - "changeFeedEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." - } - }, - "changeFeedRetentionInDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 146000, - "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." - } - }, - "containerDeleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." - } - }, - "containerDeleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." - } - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/blobCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "defaultServiceVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." - } - }, - "deleteRetentionPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob soft delete." - } - }, - "deleteRetentionPolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 365, - "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." - } - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." - } - }, - "isVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." - } - }, - "versionDeletePolicyDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." - } - }, - "lastAccessTimeTrackingPolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." - } - }, - "restorePolicyEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." - } - }, - "restorePolicyDays": { - "type": "int", - "nullable": true, - "minValue": 1, - "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Blob containers to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a blob service." - } - }, - "fileServiceType": { - "type": "object", - "properties": { - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" - }, - "description": "Optional. Protocol settings for file service." - }, - "nullable": true - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" }, - "description": "Optional. The service properties for soft delete." - }, - "nullable": true - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/fileCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a file service." - } - }, - "queueServiceType": { - "type": "object", - "properties": { - "queues": { - "type": "array", - "items": { - "$ref": "#/definitions/queueType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Queues to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/queueCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a queue service." - } - }, - "tableServiceType": { - "type": "object", - "properties": { - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/tableCorsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a table service." - } - }, - "objectReplicationPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." - } - }, - "destinationStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the destination storage account." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. The storage account object replication rules." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy." - } - }, - "_1.immutabilityPolicyType": { - "type": "object", - "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - } - }, - "metadata": { - "description": "The type for an immutability policy.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/container/main.bicep" - } - } - }, - "_2.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "parameters": { + "name": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. Name of the Azure Bastion resource." } }, - "memberName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Location for all resources." } }, - "privateIPAddress": { + "virtualNetworkResourceId": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Required. Shared services Virtual Network resource Id." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } + }, + "bastionSubnetPublicIpResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "publicIPAddressObject": { + "$ref": "#/definitions/publicIPAddressObjectType", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_2.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "blobCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "containerType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } - }, - "immutabilityPolicy": { - "$ref": "#/definitions/_1.immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" }, - "description": "Optional. A name-value pair to associate with the container as metadata." - }, - "nullable": true - }, - "publicAccess": { - "type": "string", - "allowedValues": [ - "Blob", - "Container", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type of a storage container.", - "__bicep_imported_from!": { - "sourceTemplate": "blob-service/main.bicep" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Developer", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. The SKU of this Bastion Host." + } + }, + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." + } + }, + "enableFileCopy": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." + } + }, + "enableIpConnect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." + } + }, + "enableKerberos": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." + } + }, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." + } + }, + "enableSessionRecording": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." + } + }, + "enablePrivateOnlyBastion": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." + } + }, + "scaleUnits": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/bastionHosts@2024-07-01#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "defaultValue": [], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. The list of Availability zones to use for the zone-redundant resources." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "fileCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." - } - }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, - "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "description": "The type for a file share.", - "__bicep_imported_from!": { - "sourceTemplate": "file-service/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.8.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[coalesce(parameters('tags'), createObject())]", + "sku": { + "name": "[parameters('skuName')]" + }, + "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('availabilityZones'), lambda('zone', format('{0}', lambdaVariables('zone')))))]", + "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] + }, + "azureBastion_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_diagnosticSettings": { + "copy": { + "name": "azureBastion_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "publicIPAddress": { + "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(subscription().id, resourceGroup().id, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'dnsSettings')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'idleTimeoutInMinutes')]" + }, + "ipTags": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'ipTags')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'availabilityZones'), if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "16564959277054027786" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "deleteOption": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Delete", + "Detach" + ], + "metadata": { + "description": "Optional. The delete option for the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.10.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure Bastion was deployed into." }, - "nullable": true, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } + "description": "The name the Azure Bastion." + }, + "value": "[parameters('name')]" }, - "minCreationTime": { + "resourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, - "metadata": { - "description": "The type of an object replication policy rule.", - "__bicep_imported_from!": { - "sourceTemplate": "object-replication-policy/policy/main.bicep" - } - } - }, - "permissionScopeType": { - "type": "object", - "properties": { - "permissions": { - "type": "string", - "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." - } - }, - "resourceName": { - "type": "string", - "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "description": "The resource ID the Azure Bastion." + }, + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "queueCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep", - "originalIdentifier": "corsRuleType" - } - } - }, - "queueType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the queue." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureBastion', '2025-01-01', 'full').location]" }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "ipConfAzureBastionSubnet": { + "type": "object", + "metadata": { + "description": "The Public IPconfiguration object for the AzureBastionSubnet." + }, + "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" + } } } - }, - "metadata": { - "description": "The type for a queue.", - "__bicep_imported_from!": { - "sourceTemplate": "queue-service/main.bicep" - } } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_2.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } + "description": "Resource ID of the Bastion host." }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "value": "[reference('bastionHost').outputs.resourceId.value]" }, - "sshAuthorizedKeyType": { - "type": "object", - "properties": { - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Description used to store the function/usage of the key." - } - }, - "key": { - "type": "securestring", - "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." - } - } - }, + "name": { + "type": "string", "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "local-user/main.bicep" - } - } - }, - "tableCorsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } + "description": "Name of the Bastion host." }, - "metadata": { - "description": "The type for a cors rule.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep", - "originalIdentifier": "corsRuleType" - } + "value": "[reference('bastionHost').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.virtual-machine.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('jumpboxVmName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "computerName": { + "value": "[take(variables('jumpboxVmName'), 15)]" + }, + "osType": { + "value": "Windows" + }, + "vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_D2s_v5'), createObject('value', parameters('vmSize')))]", + "adminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]", + "adminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]", + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": true + }, + "maintenanceConfigurationResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.maintenance-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "availabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 1), createObject('value', -1))]", + "imageReference": { + "value": { + "publisher": "microsoft-dsvm", + "offer": "dsvm-win-2022", + "sku": "winserver-2022", + "version": "latest" + } + }, + "osDisk": { + "value": { + "name": "[format('osdisk-{0}', variables('jumpboxVmName'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "[if(parameters('enableRedundancy'), 'Premium_LRS', 'Standard_LRS')]" } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + } + }, + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-{0}', variables('jumpboxVmName'))]", + "tags": "[parameters('tags')]", + "deleteOption": "Delete", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value)), null())]", + "ipConfigurations": [ + { + "name": "[format('{0}-nic01-ipconfig01', variables('jumpboxVmName'))]", + "subnetResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.administrationSubnetResourceId.value]", + "diagnosticSettings": "[if(parameters('enableMonitoring'), createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value)), null())]" } + ] + } + ] + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]", + "typeHandlerVersion": "1.0", + "settings": { + "mdmId": "" + } + } + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": {}, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" } }, - "metadata": { - "description": "The type for a table.", - "__bicep_imported_from!": { - "sourceTemplate": "table-service/main.bicep" - } - } + "tags": "[parameters('tags')]" + } + }, + "extensionMonitoringAgentConfig": "[if(parameters('enableMonitoring'), createObject('value', createObject('dataCollectionRuleAssociations', createArray(createObject('dataCollectionRuleResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.data-collection-rule.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value, 'name', format('send-{0}', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value))), 'enabled', true(), 'tags', parameters('tags'))), createObject('value', null()))]", + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": "[parameters('tags')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17290221824154908545" } }, "parameters": { "name": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." + "description": "Name of the virtual machine." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "extendedLocationZone": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." + "description": "Azure region for the resource." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Tags to apply to the resource." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "kind": { + "computerName": { "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], + "defaultValue": "", "metadata": { - "description": "Optional. Type of Storage Account to create." + "description": "Optional. Computer name of the virtual machine." } }, - "skuName": { + "osType": { "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_ZRS", - "Standard_GRS", - "Standard_GZRS", - "Standard_RAGRS", - "Standard_RAGZRS", - "StandardV2_LRS", - "StandardV2_ZRS", - "StandardV2_GRS", - "StandardV2_GZRS", - "Premium_LRS", - "Premium_ZRS", - "PremiumV2_LRS", - "PremiumV2_ZRS" - ], "metadata": { - "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." + "description": "Operating system type." } }, - "accessTier": { + "vmSize": { "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "Cold" - ], "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + "description": "Virtual machine size." } }, - "largeFileSharesState": { + "adminUsername": { "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" - }, - "description": "Optional. Provides the identity based authentication settings for Azure Files." - }, - "nullable": true - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } - }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + "description": "Administrator username for the virtual machine." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, - "nullable": true, + "adminPassword": { + "type": "securestring", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Administrator password for the virtual machine." } }, - "managementPolicyRules": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Optional. The Storage Account ManagementPolicies Rules." - }, - "nullable": true - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", + "managedIdentities": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." + "description": "Optional. Managed identity configuration." } }, - "customDomainName": { + "patchMode": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + "description": "Optional. Patch mode for the virtual machine." } }, - "customDomainUseSubDomainName": { + "bypassPlatformSafetyChecksOnUserSchedule": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + "description": "Optional. Whether platform safety checks should be bypassed for user schedules." } }, - "dnsEndpointType": { + "maintenanceConfigurationResourceId": { "type": "string", - "nullable": true, - "allowedValues": [ - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "$ref": "#/definitions/blobServiceType", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "$ref": "#/definitions/fileServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "$ref": "#/definitions/queueServiceType", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "$ref": "#/definitions/tableServiceType", - "defaultValue": {}, + "defaultValue": "", "metadata": { - "description": "Optional. Table service and tables to create." + "description": "Optional. Maintenance configuration resource ID." } }, - "allowBlobPublicAccess": { + "enableAutomaticUpdates": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_2", - "TLS1_3" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + "description": "Optional. Whether automatic updates are enabled." } }, - "enableSftp": { + "encryptionAtHost": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + "description": "Whether to enable encryption at host." } }, - "localUsers": { - "type": "array", - "items": { - "$ref": "#/definitions/localUserType" - }, - "nullable": true, + "availabilityZone": { + "type": "int", + "defaultValue": -1, "metadata": { - "description": "Optional. Local users to deploy for SFTP authentication." + "description": "Optional. Availability zone for the virtual machine." } }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, + "imageReference": { + "type": "object", "metadata": { - "description": "Optional. Enables local users feature, if set to true." + "description": "Image reference used to create the virtual machine." } }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, + "osDisk": { + "type": "object", "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + "description": "OS disk configuration for the virtual machine." } }, - "diagnosticSettings": { + "nicConfigurations": { "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Network interface configurations for the virtual machine." } }, - "tags": { + "extensionAadJoinConfig": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "allowedCopyScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "AAD", - "PrivateLink" - ], - "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled", - "SecuredByPerimeter" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", "nullable": true, "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "sasExpirationAction": { - "type": "string", - "defaultValue": "Log", - "allowedValues": [ - "Block", - "Log" - ], - "metadata": { - "description": "Optional. The SAS expiration action. Allowed values are Block and Log." + "description": "Optional. Azure AD join extension configuration." } }, - "keyType": { - "type": "string", + "extensionAntiMalwareConfig": { + "type": "object", "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." + "description": "Optional. Anti-malware extension configuration." } }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", + "extensionMonitoringAgentConfig": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Optional. Monitoring agent extension configuration." } }, - "immutableStorageWithVersioning": { + "extensionNetworkWatcherAgentConfig": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" - }, - "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." - }, - "nullable": true - }, - "objectReplicationPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyType" - }, "nullable": true, "metadata": { - "description": "Optional. Object replication policies for the storage account." + "description": "Optional. Network watcher extension configuration." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", - "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" - }, "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2025-05-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_roleAssignments": { - "copy": { - "name": "storageAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "virtualMachine": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[take(format('avm.res.compute.virtual-machine.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -30727,42 +11295,67 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + "value": "[parameters('name')]" }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "computerName": "[if(not(empty(parameters('computerName'))), createObject('value', parameters('computerName')), createObject('value', null()))]", + "osType": { + "value": "[parameters('osType')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "vmSize": { + "value": "[parameters('vmSize')]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "adminUsername": { + "value": "[parameters('adminUsername')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "adminPassword": { + "value": "[parameters('adminPassword')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "patchMode": "[if(not(empty(parameters('patchMode'))), createObject('value', parameters('patchMode')), createObject('value', null()))]", + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": "[parameters('bypassPlatformSafetyChecksOnUserSchedule')]" + }, + "maintenanceConfigurationResourceId": "[if(not(empty(parameters('maintenanceConfigurationResourceId'))), createObject('value', parameters('maintenanceConfigurationResourceId')), createObject('value', null()))]", + "enableAutomaticUpdates": { + "value": "[parameters('enableAutomaticUpdates')]" + }, + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" + }, + "availabilityZone": { + "value": "[parameters('availabilityZone')]" + }, + "imageReference": { + "value": "[parameters('imageReference')]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "osDisk": { + "value": "[parameters('osDisk')]" + }, + "nicConfigurations": { + "value": "[parameters('nicConfigurations')]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "extensionAadJoinConfig": { + "value": "[parameters('extensionAadJoinConfig')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "extensionAntiMalwareConfig": { + "value": "[parameters('extensionAntiMalwareConfig')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "extensionMonitoringAgentConfig": { + "value": "[parameters('extensionMonitoringAgentConfig')]" + }, + "extensionNetworkWatcherAgentConfig": { + "value": "[parameters('extensionNetworkWatcherAgentConfig')]" } }, "template": { @@ -30772,1192 +11365,1687 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" + "version": "0.41.2.15936", + "templateHash": "17174537341033050778" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." + }, + "definitions": { + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "diffDiskSettings": { + "type": "object", + "properties": { + "placement": { + "type": "string", + "allowedValues": [ + "CacheDisk", + "NvmeDisk", + "ResourceDisk" + ], + "metadata": { + "description": "Required. Specifies the ephemeral disk placement for the operating system disk." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing an OS disk." + } + }, + "dataDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name. When attaching a pre-existing disk, this name is ignored and the name of the existing disk is used." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes. This property is ignored when attaching a pre-existing disk." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created. This property is automatically set to 'Attach' when attaching a pre-existing disk." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion. This property is automatically set to 'Detach' when attaching a pre-existing disk." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements. This property is automatically set to 'None' when attaching a pre-existing disk." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. Ignored when attaching a pre-existing disk." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. Ignored when attaching a pre-existing disk." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk. Ignored when attaching a pre-existing disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource id of a pre-existing managed disk. If the disk should be created, this property should be empty." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/disks@2025-01-02#properties/tags" + }, + "description": "Optional. The tags of the public IP address. Valid only when creating a new managed disk." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a data disk." + } }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { + "publicKeyType": { + "type": "object", + "properties": { + "keyData": { + "type": "string", + "metadata": { + "description": "Required. Specifies the SSH public key data used to authenticate through ssh." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." + } + } + } + }, + "nicConfigurationType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. The name of the NIC configuration." } }, - "privateDnsZoneGroupConfigs": { + "nicSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The suffix to append to the NIC name." + } + }, + "enableIPForwarding": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify what happens to the network interface when the VM is deleted." + } + }, + "dnsServers": { "type": "array", "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "type": "string" }, + "nullable": true, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "metadata": { + "description": "Required. The IP configurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the NIC configuration." + } + }, + "imageReferenceType": { + "type": "object", + "properties": { + "communityGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the community gallery image unique id for vm deployment. This can be fetched from community gallery image GET call." + } + }, + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource Id of the image reference." + } + }, + "offer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the offer of the platform image or marketplace image used to create the virtual machine." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The image publisher." + } + }, + "sku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SKU of the image." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the platform image or marketplace image used to create the virtual machine. The allowed formats are Major.Minor.Build or 'latest'. Even if you use 'latest', the VM image will not automatically update after deploy time even if a new version becomes available." + } + }, + "sharedGalleryImageId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specified the shared gallery image unique id for vm deployment. This can be fetched from shared gallery image GET call." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the image reference." + } + }, + "planType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the plan." + } + }, + "product": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the product of the image from the marketplace." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher ID." + } + }, + "promotionCode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The promotion code." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Specifies information about the marketplace image used to create the virtual machine." + } + }, + "autoShutDownConfigType": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the auto shutdown configuration." + } + }, + "timeZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time zone ID (e.g. China Standard Time, Greenland Standard Time, Pacific Standard time, etc.)." + } + }, + "dailyRecurrenceTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time of day the schedule will occur." + } + }, + "notificationSettings": { + "type": "object", + "properties": { + "status": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The status of the notification settings." + } + }, + "emailRecipient": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The email address to send notifications to (can be a list of semi-colon separated email addresses)." + } + }, + "notificationLocale": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The locale to use when sending a notification (fallback for unsupported languages is EN)." + } + }, + "webhookUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The webhook URL to which the notification will be sent." + } + }, + "timeInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The time in minutes before shutdown to send notifications." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the schedule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the configuration profile." + } + }, + "vaultSecretGroupType": { + "type": "object", + "properties": { + "sourceVault": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The relative URL of the Key Vault containing all of the certificates in VaultCertificates." + } + }, + "vaultCertificates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "certificateStore": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. For Windows VMs, specifies the certificate store on the Virtual Machine to which the certificate should be added. The specified certificate store is implicitly in the LocalMachine account. For Linux VMs, the certificate file is placed under the /var/lib/waagent directory, with the file name .crt for the X509 certificate file and .prv for private key. Both of these files are .pem formatted." + } + }, + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the URL of a certificate that has been uploaded to Key Vault as a secret." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of key vault references in SourceVault which contain certificates." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the set of certificates that should be installed onto the virtual machine." + } + }, + "vmGalleryApplicationType": { + "type": "object", + "properties": { + "packageReferenceId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the GalleryApplicationVersion resource id on the form of /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/applications/{application}/versions/{version}." + } + }, + "configurationReference": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the uri to an azure blob that will replace the default configuration for the package if provided." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If set to true, when a new Gallery Application version is available in PIR/SIG, it will be automatically updated for the VM/VMSS." + } + }, + "order": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the order in which the packages have to be installed." + } + }, + "tags": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies a passthrough value for more generic context." + } + }, + "treatFailureAsDeploymentFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If true, any failure for any operation in the VmApplication will fail the deployment." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the gallery application that should be made available to the VM/VMSS." + } + }, + "additionalUnattendContentType": { + "type": "object", + "properties": { + "settingName": { + "type": "string", + "allowedValues": [ + "AutoLogon", + "FirstLogonCommands" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the setting to which the content applies." + } + }, + "content": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the XML formatted content that is added to the unattend.xml file for the specified path and component. The XML must be less than 4KB and must include the root element for the setting or feature that is being inserted." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup." + } + }, + "winRMListenerType": { + "type": "object", + "properties": { + "certificateUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The URL of a certificate that has been uploaded to Key Vault as a secret." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Http", + "Https" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the protocol of WinRM listener." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing a Windows Remote Management listener." + } + }, + "nicConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NIC configuration." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "Required. List of IP configurations of the NIC configuration." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type describing the network interface configuration output." + } + }, + "extensionCustomScriptConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual machine extension. Defaults to `CustomScriptExtension`." + } + }, + "typeHandlerVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the version of the script handler. Defaults to `1.10` for Windows and `2.1` for Linux." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. Defaults to `true`." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. If the command contains any credentials, use the same property of the `protectedSettings` instead. Required if `protectedSettings.commandToExecute` is not provided." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded. If URLs are sensitive, for example, if they contain keys, this field should be specified in `protectedSettings`." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "protectedSettings": { + "type": "secureObject", + "properties": { + "commandToExecute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The entry point script to run. Use this property if your command contains secrets such as passwords or if your file URIs are sensitive. Required if `settings.commandToExecute` is not provided." + } + }, + "storageAccountName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of storage account. If you specify storage credentials, all fileUris values must be URLs for Azure blobs.." + } + }, + "storageAccountKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The access key of the storage account." + } + }, + "managedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity for downloading files. Must not be used in conjunction with the `storageAccountName` or `storageAccountKey` property. If you want to use the VM's system assigned identity, set the `value` to an empty string." + } + }, + "fileUris": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. URLs for files to be downloaded." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The configuration of the custom script extension. Note: You can provide any property either in the `settings` or `protectedSettings` but not both. If your property contains secrets, use `protectedSettings`." + } + }, + "supressFailures": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). Defaults to `false`." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. Defaults to `false`." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "The type of a private dns zone group." + "description": "The type of a 'CustomScriptExtension' extension." } }, - "lockType": { + "_1.applicationGatewayBackendAddressPoolsType": { "type": "object", "properties": { - "name": { + "id": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. Resource ID of the backend address pool." } }, - "kind": { + "name": { "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." } }, - "notes": { - "type": "string", + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. Properties of the application gateway backend address pool." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", + "description": "The type for the application gateway backend address pool.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" } } }, - "privateDnsZoneGroupConfigType": { + "_1.applicationSecurityGroupType": { "type": "object", "properties": { - "name": { + "id": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Resource ID of the application security group." } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { + "location": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. Location of the application security group." } }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], + "properties": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Properties of the application security group." } }, - "description": { - "type": "string", + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Tags of the application security group." } - }, - "condition": { + } + }, + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "_1.backendAddressPoolType": { + "type": "object", + "properties": { + "id": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. The resource ID of the backend address pool." } }, - "conditionVersion": { + "name": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The name of the backend address pool." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "properties": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The properties of the backend address pool." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", + "description": "The type for a backend address pool.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" } } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { + "_1.inboundNatRuleType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, + "backendPort": { + "type": "int", + "nullable": true, "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." } }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, + "enableTcpReset": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." } }, - "name": { - "type": "string", - "defaultValue": "default", + "frontendIPConfiguration": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. A reference to frontend IP addresses." } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." } - } - }, - "outputs": { - "name": { - "type": "string", + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } }, - "resourceId": { - "type": "string", + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } }, - "resourceGroupName": { + "protocol": { "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." } } }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_managementPolicies": { - "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "rules": { - "value": "[variables('formattedManagementPolicies')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "4000605059554016072" - }, - "name": "Storage Account Management Policies", - "description": "This module deploys a Storage Account Management Policy." - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "rules": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" - }, - "description": "Required. The Storage Account ManagementPolicies Rules." + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "_1.subResourceType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." } } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } } }, - { - "type": "Microsoft.Storage/storageAccounts/managementPolicies", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "_1.virtualNetworkTapType": { + "type": "object", "properties": { - "policy": { - "rules": "[parameters('rules')]" + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed management policy." - }, - "value": "default" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed management policy." }, - "value": "default" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The resource group of the deployed management policy." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] - }, - "storageAccount_localUsers": { - "copy": { - "name": "storageAccount_localUsers", - "count": "[length(coalesce(parameters('localUsers'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" - }, - "hasSshKey": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" - }, - "hasSshPassword": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" - }, - "permissionScopes": { - "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" - }, - "hasSharedKey": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" - }, - "homeDirectory": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" - }, - "sshAuthorizedKeys": { - "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1801226901235196767" + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "name": "Storage Account Local Users", - "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." - }, - "definitions": { - "sshAuthorizedKeyType": { + "_2.ddosSettingsType": { "type": "object", "properties": { - "description": { - "type": "string", + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, "nullable": true, "metadata": { - "description": "Optional. Description used to store the function/usage of the key." + "description": "Optional. The DDoS protection plan associated with the public IP address." } }, - "key": { - "type": "securestring", + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], "metadata": { - "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + "description": "Required. The DDoS protection policy customizations." } } }, "metadata": { - "__bicep_export!": true + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } } }, - "permissionScopeType": { + "_2.dnsSettingsType": { "type": "object", "properties": { - "permissions": { + "domainNameLabel": { "type": "string", "metadata": { - "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." } }, - "resourceName": { + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." } }, - "service": { + "reverseFqdn": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The service used by the local user, e.g. blob, file." + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." } } }, "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the local user used for SFTP Authentication." - } - }, - "hasSharedKey": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." - } - }, - "hasSshKey": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." - } - }, - "hasSshPassword": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." - } - }, - "homeDirectory": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The local user home directory." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } } }, - "permissionScopes": { - "type": "array", - "items": { - "$ref": "#/definitions/permissionScopeType" + "_2.ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } }, "metadata": { - "description": "Required. The permission scopes of the local user." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } } }, - "sshAuthorizedKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/sshAuthorizedKeyType" + "_3.diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. The local user SSH authorized keys for SFTP." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "_3.lockType": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." } } - } - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "localUsers": { - "type": "Microsoft.Storage/storageAccounts/localUsers", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "hasSharedKey": "[parameters('hasSharedKey')]", - "hasSshKey": "[parameters('hasSshKey')]", - "hasSshPassword": "[parameters('hasSshPassword')]", - "homeDirectory": "[parameters('homeDirectory')]", - "permissionScopes": "[parameters('permissionScopes')]", - "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed local user." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed local user." }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed local user." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_blobServices": { - "condition": "[not(empty(parameters('blobServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "containers": { - "value": "[tryGet(parameters('blobServices'), 'containers')]" - }, - "automaticSnapshotPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" - }, - "changeFeedEnabled": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" - }, - "changeFeedRetentionInDays": { - "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" - }, - "containerDeleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" - }, - "containerDeleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" - }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" - }, - "corsRules": { - "value": "[tryGet(parameters('blobServices'), 'corsRules')]" - }, - "defaultServiceVersion": { - "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" - }, - "deleteRetentionPolicyAllowPermanentDelete": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" - }, - "deleteRetentionPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" - }, - "deleteRetentionPolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" - }, - "isVersioningEnabled": { - "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" - }, - "lastAccessTimeTrackingPolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" - }, - "restorePolicyEnabled": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" - }, - "restorePolicyDays": { - "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "468225492069709453" + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "name": "Storage Account blob Services", - "description": "This module deploys a Storage Account Blob Service." - }, - "definitions": { - "corsRuleType": { + "_3.roleAssignmentType": { "type": "object", "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, + "name": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "allowedMethods": { - "type": "array", + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" ], + "nullable": true, "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + "description": "Optional. The principal type of the assigned principal ID." } }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, + "description": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + "description": "Optional. The description of the role assignment." } }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, + "condition": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "maxAgeInSeconds": { - "type": "int", + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "containerType": { + "_4.publicIPConfigurationType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the Storage Container to deploy." + "description": "Optional. The name of the Public IP Address." } }, - "defaultEncryptionScope": { + "publicIPAddressResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." + "description": "Optional. The resource ID of the public IP address." } }, - "denyEncryptionScopeOverride": { - "type": "bool", + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, "nullable": true, "metadata": { - "description": "Optional. Block override of encryption scope from the container default." + "description": "Optional. Diagnostic settings for the public IP address." } }, - "enableNfsV3AllSquash": { - "type": "bool", + "location": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." + "description": "Optional. The idle timeout in minutes." } }, - "enableNfsV3RootSquash": { - "type": "bool", + "lock": { + "$ref": "#/definitions/_3.lockType", "nullable": true, "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." + "description": "Optional. The lock settings of the public IP address." } }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", + "idleTimeoutInMinutes": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + "description": "Optional. The idle timeout of the public IP address." } }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", + "ddosSettings": { + "$ref": "#/definitions/_2.ddosSettingsType", "nullable": true, "metadata": { - "description": "Optional. Configure immutability policy." + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." } }, - "metadata": { + "dnsSettings": { + "$ref": "#/definitions/_2.dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" }, - "description": "Optional. A name-value pair to associate with the container as metadata." + "description": "Optional. The tags of the public IP address." }, "nullable": true }, - "publicAccess": { - "type": "string", + "availabilityZones": { + "type": "array", "allowedValues": [ - "Blob", - "Container", - "None" + 1, + 2, + 3 ], "nullable": true, "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + "description": "Optional. The zones of the public IP address." } }, - "roleAssignments": { + "ipTags": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" + "$ref": "#/definitions/_2.ipTagType" }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a storage container." + "description": "The type for the public IP address configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } } }, "diagnosticSettingFullType": { @@ -32064,53 +13152,261 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer backend address pools." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application security groups." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The application gateway backend address pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/_1.subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address version." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/_4.publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/_3.diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." + } + } + }, + "metadata": { + "description": "The type for the IP configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "modules/nic-configuration.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." } }, - "marketplacePartnerResourceId": { - "type": "string", + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "immutabilityPolicyType": { + "networkInterfaceIPConfigurationOutputType": { "type": "object", "properties": { - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "nullable": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + "description": "The name of the IP configuration." } }, - "allowProtectedAppendWrites": { - "type": "bool", + "privateIP": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + "description": "The private IP address." } }, - "allowProtectedAppendWritesAll": { - "type": "bool", + "publicIP": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + "description": "The public IP address." } } }, "metadata": { - "description": "The type for an immutability policy.", + "description": "The type for the network interface IP configuration output.", "__bicep_imported_from!": { - "sourceTemplate": "container/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" } } }, @@ -32185,283 +13481,1038 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.3" } } } }, "parameters": { - "storageAccountName": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Required. Specifies the size for the VMs." } }, - "automaticSnapshotPolicyEnabled": { + "encryptionAtHost": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Automatic Snapshot is enabled if set to true." + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." } }, - "changeFeedEnabled": { + "securityType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/securityProfile/properties/securityType" + }, + "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." + }, + "nullable": true + }, + "secureBootEnabled": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." } }, - "changeFeedRetentionInDays": { - "type": "int", + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2025-04-01#properties/properties/properties/storageProfile/properties/imageReference" + }, + "description": "Conditional. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. Required if not creating the VM from an existing os-disk via the `osDisk.managedDisk.resourceId` parameter." + }, + "nullable": true + }, + "plan": { + "$ref": "#/definitions/planType", + "nullable": true, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "type": "array", + "items": { + "$ref": "#/definitions/dataDiskType" + }, "nullable": true, - "minValue": 1, - "maxValue": 146000, "metadata": { - "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." } }, - "containerDeleteRetentionPolicyEnabled": { + "ultraSSDEnabled": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." } }, - "containerDeleteRetentionPolicyDays": { - "type": "int", + "hibernationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables hibernation capability on the VM." + } + }, + "adminUsername": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. Administrator username. Required if no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty)." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, and no pre-existing OS-Disk is provided (osDisk.managedDisk.resourceId is not empty), this value should be passed." + } + }, + "userData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "items": { + "$ref": "#/definitions/vaultSecretGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "Deallocate", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "publicKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/publicKeyType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, - "minValue": 1, - "maxValue": 365, "metadata": { - "description": "Optional. Indicates the number of days that the deleted item should be retained." + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." } }, - "containerDeleteRetentionPolicyAllowPermanentDelete": { + "bootDiagnostics": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "galleryApplications": { + "type": "array", + "items": { + "$ref": "#/definitions/vmGalleryApplicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." + } + }, + "availabilityZone": { + "type": "int", + "allowedValues": [ + -1, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If set to -1, no zone is defined. Note that the availability zone numbers here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone. To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones)." } }, - "corsRules": { + "nicConfigurations": { "type": "array", "items": { - "$ref": "#/definitions/corsRuleType" + "$ref": "#/definitions/nicConfigurationType" + }, + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Recovery service vault name to add VMs to backup." + } + }, + "backupVaultResourceGroup": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "DefaultPolicy", + "metadata": { + "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + } + }, + "autoShutdownConfig": { + "$ref": "#/definitions/autoShutDownConfigType", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for auto-shutdown." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource Id of a maintenance configuration for this VM." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "dataCollectionRuleAssociations": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "$ref": "#/definitions/extensionCustomScriptConfigType", "nullable": true, "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + "description": "Optional. The configuration for the [Custom Script] extension." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionHostPoolRegistration": { + "type": "secureObject", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "extensionGuestConfigurationExtension": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identity." + } + }, + "guestConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." + } + }, + "extensionGuestConfigurationExtensionProtectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." } }, - "defaultServiceVersion": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + "description": "Optional. Array of role assignments to create." } }, - "deleteRetentionPolicyEnabled": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. The blob service properties for blob soft delete." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "deleteRetentionPolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, - "maxValue": 365, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], "metadata": { - "description": "Optional. Indicates the number of days that the deleted blob should be retained." + "description": "Required. The chosen OS type." } }, - "deleteRetentionPolicyAllowPermanentDelete": { + "disablePasswordAuthentication": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + "description": "Optional. Specifies whether password authentication should be disabled." } }, - "isVersioningEnabled": { + "provisionVMAgent": { "type": "bool", - "defaultValue": false, + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], "metadata": { - "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." } }, - "lastAccessTimeTrackingPolicyEnabled": { + "enableHotpatching": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "items": { + "$ref": "#/definitions/additionalUnattendContentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRMListeners": { + "type": "array", + "items": { + "$ref": "#/definitions/winRMListenerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + }, + "capacityReservationGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Capacity reservation group resource id that should be used for allocating the virtual machine vm instances provided enough capacity has been reserved." + } + }, + "networkAccessPolicy": { + "type": "string", + "defaultValue": "DenyAll", + "allowedValues": [ + "AllowAll", + "AllowPrivate", + "DenyAll" + ], + "metadata": { + "description": "Optional. Policy for accessing the disk via network." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Policy for controlling export on the disk." + } + } + }, + "variables": { + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" + } + }, + { + "name": "additionalUnattendContentFormatted", + "count": "[length(coalesce(parameters('additionalUnattendContent'), createArray()))]", + "input": { + "settingName": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].settingName]", + "content": "[coalesce(parameters('additionalUnattendContent'), createArray())[copyIndex('additionalUnattendContentFormatted')].content]", + "componentName": "Microsoft-Windows-Shell-Setup", + "passName": "OobeSystem" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), variables('additionalUnattendContentFormatted'))]", + "winRM": "[if(not(empty(parameters('winRMListeners'))), createObject('listeners', parameters('winRMListeners')), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" + }, + "aadJoinSettings": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]", + "filteredAadJoinSettings": "[if(and(contains(variables('aadJoinSettings'), 'mdmId'), empty(variables('aadJoinSettings').mdmId)), reduce(items(variables('aadJoinSettings')), createObject(), lambda('cur', 'item', if(equals(lambdaVariables('item').key, 'mdmId'), lambdaVariables('cur'), union(lambdaVariables('cur'), createObject(format('{0}', lambdaVariables('item').key), lambdaVariables('item').value))))), variables('aadJoinSettings'))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.22.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "restorePolicyEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." - } + "managedDataDisks": { + "copy": { + "name": "managedDataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" + }, + "condition": "[and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty'), 'FromImage')))]", + "type": "Microsoft.Compute/disks", + "apiVersion": "2025-01-02", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", + "location": "[parameters('location')]", + "sku": { + "name": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType')]" + }, + "properties": { + "diskSizeGB": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskSizeGB')]", + "creationData": { + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createOption'), 'Empty')]" + }, + "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", + "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "networkAccessPolicy": "[parameters('networkAccessPolicy')]" + }, + "zones": "[if(and(not(equals(parameters('availabilityZone'), -1)), not(contains(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk, 'storageAccountType'), ''), 'ZRS'))), array(string(parameters('availabilityZone'))), null())]", + "tags": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('availabilityZone'), -1)), array(string(parameters('availabilityZone'))), null())]", + "plan": "[parameters('plan')]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": "[shallowMerge(createArray(if(parameters('encryptionAtHost'), createObject('encryptionAtHost', parameters('encryptionAtHost')), createObject()), createObject('securityType', parameters('securityType'), 'uefiSettings', if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null()))))]", + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), last(split(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.resourceId, '/')), coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", + "createOption": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), 'FromImage', if(or(not(equals(if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null()), null())), not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')))), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty')))]", + "deleteOption": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete'))]", + "caching": "[if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'))), 'None', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly'))]", + "diskSizeGB": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), null(), tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'diskSizeGB'))]", + "managedDisk": "[if(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'), createObject('storageAccountType', tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'storageAccountType'), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())), createObject('id', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId'), if(and(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'resourceId')), not(equals(coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createOption'), 'Empty'), 'FromImage'))), resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'diskEncryptionSet', if(not(empty(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.diskEncryptionSetResourceId), null())))]" + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), last(split(parameters('osDisk').managedDisk.resourceId, '/')), coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name'))))]", + "createOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Attach', coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage'))]", + "osType": "[parameters('osType')]", + "deleteOption": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'Detach', coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete'))]", + "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", + "diskSizeGB": "[tryGet(parameters('osDisk'), 'diskSizeGB')]", + "caching": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId'))), 'None', coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly'))]", + "managedDisk": { + "storageAccountType": "[tryGet(parameters('osDisk').managedDisk, 'storageAccountType')]", + "diskEncryptionSet": "[if(not(empty(tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId'))), createObject('id', tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')), null())]", + "id": "[tryGet(parameters('osDisk').managedDisk, 'resourceId')]" + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]", + "hibernationEnabled": "[parameters('hibernationEnabled')]" + }, + "osProfile": "[if(empty(tryGet(parameters('osDisk').managedDisk, 'resourceId')), createObject('computerName', parameters('computerName'), 'adminUsername', parameters('adminUsername'), 'adminPassword', parameters('adminPassword'), 'customData', if(not(empty(parameters('customData'))), base64(parameters('customData')), null()), 'windowsConfiguration', if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null()), 'linuxConfiguration', if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null()), 'secrets', parameters('certificatesToBeInstalled'), 'allowExtensionOperations', parameters('allowExtensionOperations')), null())]", + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" + } + } + ] + }, + "capacityReservation": "[if(not(empty(parameters('capacityReservationGroupResourceId'))), createObject('capacityReservationGroup', createObject('id', parameters('capacityReservationGroupResourceId'))), null())]", + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostResourceId'))), createObject('id', parameters('dedicatedHostResourceId')), null())]", + "licenseType": "[parameters('licenseType')]", + "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" + }, + "dependsOn": [ + "managedDataDisks", + "vm_nic" + ] + }, + "vm_configurationAssignment": { + "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", + "type": "Microsoft.Maintenance/configurationAssignments", + "apiVersion": "2023-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[format('{0}assignment', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", + "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "dependsOn": [ + "vm" + ] }, - "restorePolicyDays": { - "type": "int", - "defaultValue": 7, - "minValue": 1, - "metadata": { - "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." - } + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" + "vm_autoShutdownConfiguration": { + "condition": "[not(empty(parameters('autoShutdownConfig')))]", + "type": "Microsoft.DevTestLab/schedules", + "apiVersion": "2018-09-15", + "name": "[format('shutdown-computevm-{0}', parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'tags'), parameters('tags'))]", + "properties": { + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", + "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "taskType": "ComputeVmShutdownTask", + "dailyRecurrence": { + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" + }, + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationSettings'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled'), 'emailRecipient', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'emailRecipient'), ''), 'notificationLocale', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'webhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(tryGet(parameters('autoShutdownConfig'), 'notificationSettings'), 'timeInMinutes'), 30)), null())]" }, - "nullable": true, - "metadata": { - "description": "Optional. Blob containers to create." - } + "dependsOn": [ + "vm" + ] }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "vm_dataCollectionRuleAssociations": { + "copy": { + "name": "vm_dataCollectionRuleAssociations", + "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false, - "name": "default" - }, - "resources": { - "storageAccount": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2024-03-11", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", + "properties": { + "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "cseIdentity": { + "condition": "[not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId')))]", "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/')[4]]", + "name": "[last(split(parameters('extensionCustomScriptConfig').protectedSettings.managedIdentityResourceId, '/'))]" + }, + "AzureWindowsBaseline": { + "condition": "[not(empty(parameters('guestConfiguration')))]", + "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", + "apiVersion": "2024-04-05", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('guestConfiguration'), 'name'), 'AzureWindowsBaseline')]", + "location": "[parameters('location')]", + "properties": { + "guestConfiguration": "[parameters('guestConfiguration')]" + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] }, - "blobServices": { - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "vm_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { - "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", - "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", - "containerDeleteRetentionPolicy": { - "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", - "days": "[parameters('containerDeleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" - }, - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "defaultServiceVersion": "[parameters('defaultServiceVersion')]", - "deleteRetentionPolicy": { - "enabled": "[parameters('deleteRetentionPolicyEnabled')]", - "days": "[parameters('deleteRetentionPolicyDays')]", - "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" - }, - "isVersioningEnabled": "[parameters('isVersioningEnabled')]", - "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", - "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "storageAccount" + "vm" ] }, - "blobServices_diagnosticSettings": { + "vm_roleAssignments": { "copy": { - "name": "blobServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "name": "vm_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "blobServices" + "vm" ] }, - "blobServices_container": { + "vm_nic": { "copy": { - "name": "blobServices_container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" }, - "blobServiceName": { - "value": "[variables('name')]" + "virtualMachineName": { + "value": "[parameters('name')]" }, - "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + "location": { + "value": "[parameters('location')]" }, - "defaultEncryptionScope": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" }, - "denyEncryptionScopeOverride": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" }, - "enableNfsV3AllSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers'))), createObject('value', tryGet(parameters('nicConfigurations')[copyIndex()], 'dnsServers')), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" }, - "enableNfsV3RootSquash": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" }, - "immutableStorageWithVersioningEnabled": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + "lock": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" }, - "metadata": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" }, - "publicAccess": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "immutabilityPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" @@ -32475,1099 +14526,848 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "273904034769611992" - }, - "name": "Storage Account Blob Containers", - "description": "This module deploys a Storage Account Blob Container." + "templateHash": "5982155361487304817" + } }, "definitions": { - "immutabilityPolicyType": { + "publicIPConfigurationType": { "type": "object", "properties": { - "immutabilityPeriodSinceCreationInDays": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Public IP Address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings for the public IP address." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The idle timeout in minutes." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the public IP address." + } + }, + "idleTimeoutInMinutes": { "type": "int", "nullable": true, "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + "description": "Optional. The idle timeout of the public IP address." } }, - "allowProtectedAppendWrites": { - "type": "bool", + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." } }, - "allowProtectedAppendWritesAll": { + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "publicIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpNameSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name suffix of the public IP address resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "skuName": { + "type": "string", + "allowedValues": [ + "Basic", + "Standard" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the public IP address." + } + }, + "skuTier": { + "type": "string", + "allowedValues": [ + "Global", + "Regional" + ], + "nullable": true, + "metadata": { + "description": "Optional. The SKU tier of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "availabilityZones": { + "type": "array", + "allowedValues": [ + 1, + 2, + 3 + ], + "nullable": true, + "metadata": { + "description": "Optional. The zones of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "enableTelemetry": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + "description": "Optional. Enable/Disable usage telemetry for the module." } } }, "metadata": { "__bicep_export!": true, - "description": "The type for an immutability policy." + "description": "The type for the public IP address configuration." } }, - "roleAssignmentType": { + "ipConfigurationType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + "description": "Optional. The name of the IP configuration." } }, - "roleDefinitionIdOrName": { + "privateIPAllocationMethod": { "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The private IP address allocation method." } }, - "principalId": { + "privateIPAddress": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The private IP address." } }, - "principalType": { + "subnetResourceId": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. The load balancer backend address pools." } }, - "description": { - "type": "string", + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. The application security groups." } }, - "condition": { - "type": "string", + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "Optional. The application gateway backend address pools." } }, - "conditionVersion": { + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The gateway load balancer settings." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The load balancer inbound NAT rules." + } + }, + "privateIPAddressVersion": { "type": "string", "allowedValues": [ - "2.0" + "IPv4", + "IPv6" ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The private IP address version." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. The virtual network taps." + } + }, + "pipConfiguration": { + "$ref": "#/definitions/publicIPConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The public IP address configuration." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the IP configuration." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. The tags of the public IP address." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for the module." } } }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "blobServiceName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Storage Container to deploy." - } - }, - "defaultEncryptionScope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Default the container to use specified encryption scope for all writes." - } - }, - "denyEncryptionScopeOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Block override of encryption scope from the container default." - } - }, - "enableNfsV3AllSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 all squash on blob container." - } - }, - "enableNfsV3RootSquash": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable NFSv3 root squash on blob container." - } - }, - "immutableStorageWithVersioningEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." - } - }, - "immutabilityPolicy": { - "$ref": "#/definitions/immutabilityPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Configure immutability policy." + "__bicep_export!": true, + "description": "The type for the IP configuration." } }, - "metadata": { + "applicationGatewayBackendAddressPoolsType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. A name-value pair to associate with the container as metadata." - }, - "defaultValue": {} - }, - "publicAccess": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Container", - "Blob", - "None" - ], - "metadata": { - "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", - "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount::blobServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." } } + }, + "metadata": { + "description": "The type for the application gateway backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "container": { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", - "properties": { - "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", - "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", - "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", - "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", - "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", - "metadata": "[parameters('metadata')]", - "publicAccess": "[parameters('publicAccess')]" - } - }, - "container_roleAssignments": { - "copy": { - "name": "container_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "applicationSecurityGroupType": { + "type": "object", "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } }, - "dependsOn": [ - "container" - ] + "metadata": { + "description": "The type for the application security group.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } }, - "container_immutabilityPolicy": { - "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "backendAddressPoolType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "containerName": { - "value": "[parameters('name')]" - }, - "immutabilityPeriodSinceCreationInDays": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" - }, - "allowProtectedAppendWrites": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" - }, - "allowProtectedAppendWritesAll": { - "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", + "properties": { + "type": "object", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "15304742179563677019" - }, - "name": "Storage Account Blob Container Immutability Policies", - "description": "This module deploys a Storage Account Blob Container Immutability Policy." - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "containerName": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "description": "The type for a backend address pool.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." - } - }, - "immutabilityPeriodSinceCreationInDays": { - "type": "int", - "defaultValue": 365, - "metadata": { - "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." - } - }, - "allowProtectedAppendWrites": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - }, - "allowProtectedAppendWritesAll": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." } } }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - { - "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", - "properties": { - "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", - "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", - "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" - } - } + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed immutability policy." - }, - "value": "default" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed immutability policy." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed immutability policy." - }, - "value": "[resourceGroup().name]" - } + "metadata": { + "description": "Required. The DDoS protection policy customizations." } } }, - "dependsOn": [ - "container" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed container." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed container." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed container." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "blobServices" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed blob service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the deployed blob service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - }, - "corsRules": { - "value": "[tryGet(parameters('fileServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "17583198711200998285" - }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "fileShareType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share." - } - }, - "accessTier": { - "type": "string", - "allowedValues": [ - "Cool", - "Hot", - "Premium", - "TransactionOptimized" - ], - "nullable": true, - "metadata": { - "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "enabledProtocols": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "nullable": true, - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "shareQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "provisionedBandwidthMibps": { - "type": "int", - "nullable": true, - "maxValue": 10340, - "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." - } - }, - "provisionedIops": { - "type": "int", - "nullable": true, - "maxValue": 102400, - "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a file share." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "The type for the inbound NAT rule.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/public-ip-address:0.8.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" - }, - "description": "Optional. Protocol settings for file service." - }, - "defaultValue": {} - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" - }, - "description": "Optional. The service properties for soft delete." - }, - "defaultValue": { - "enabled": true, - "days": 7 - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "items": { - "$ref": "#/definitions/fileShareType" - }, - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "variables": { - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } - }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "fileServices" - ] - }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" - }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" - }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" - }, - "provisionedBandwidthMibps": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" - }, - "provisionedIops": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "10353179772982843397" }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share." - }, - "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -33642,95 +15442,134 @@ "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "The type for the sub resource.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } } }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + "description": "The type for the virtual network tap.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-interface:0.5.1" + } } + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share to create." + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" } }, - "accessTier": { + "location": { "type": "string", - "nullable": true, - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + "description": "Optional. Location for all resources." } }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + "description": "Optional. Tags of the resource." } }, - "enabledProtocols": { - "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." } }, - "rootSquash": { + "networkSecurityGroupResourceId": { "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], + "defaultValue": "", "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + "description": "Optional. The network security group (NSG) to attach to the network interface." } }, - "provisionedBandwidthMibps": { - "type": "int", + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, - "minValue": 0, - "maxValue": 10340, "metadata": { - "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + "description": "Optional. The lock settings of the service." } }, - "provisionedIops": { - "type": "int", + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, "nullable": true, - "minValue": 0, - "maxValue": 102400, - "metadata": { - "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The diagnostic settings of the service." } }, "roleAssignments": { @@ -33744,735 +15583,1817 @@ } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(not(empty(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'))), empty(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressResourceId')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpNameSuffix')))]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'diagnosticSettings'), tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'dnsSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'publicIpPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "availabilityZones": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'availabilityZones')]" + }, + "enableTelemetry": { + "value": "[coalesce(coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'enableTelemetry'), tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry')), parameters('enableTelemetry'))]" + }, + "ipTags": { + "value": "[tryGet(tryGet(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), 'ipTags')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "5349747633189946992" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAllocationMethod" + }, + "description": "Optional. The public IP address allocation method." + }, + "defaultValue": "Static" + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/publicIPAddressVersion" + }, + "description": "Optional. IP address version." + }, + "defaultValue": "IPv4" + }, + "dnsSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/dnsSettings" + }, + "description": "Optional. The DNS settings of the public IP address." + }, + "nullable": true + }, + "ipTags": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ipTags" + }, + "description": "Optional. The list of tags associated with the public IP address." + }, + "nullable": true + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/name" + }, + "description": "Optional. Name of a public IP address SKU." + }, + "defaultValue": "Standard" + }, + "skuTier": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/sku/properties/tier" + }, + "description": "Optional. Tier of a public IP address SKU." + }, + "defaultValue": "Regional" + }, + "ddosSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/ddosSettings" + }, + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + }, + "nullable": true + }, + "deleteOption": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/properties/properties/deleteOption" + }, + "description": "Optional. The delete option for the public IP address." + }, + "nullable": true + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/publicIPAddresses@2025-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2025-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('availabilityZones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]", + "deleteOption": "[parameters('deleteOption')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2025-01-01', 'full').location]" } } } } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" - }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]", - "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", - "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "fileShare_roleAssignments": { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, + "networkInterface": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[format('{0}-NetworkInterface', deployment().name)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "scope": { - "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" - }, "name": { - "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + "value": "[parameters('networkInterfaceName')]" }, - "roleDefinitionId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'name'), 'privateIPAllocationMethod', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), 'privateIPAddress', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), 'publicIPAddressResourceId', if(not(empty(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'))), if(not(contains(coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), createObject()), 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), 'publicIpNameSuffix')))), tryGet(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration', 'publicIPAddressResourceId')), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), 'applicationSecurityGroups', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), 'applicationGatewayBackendAddressPools', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), 'gatewayLoadBalancer', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), 'loadBalancerInboundNatRules', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), 'privateIPAddressVersion', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), 'virtualNetworkTaps', tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'))]" + } + ] }, - "principalId": { - "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + "location": { + "value": "[parameters('location')]" }, - "principalType": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + "tags": { + "value": "[parameters('tags')]" }, - "condition": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "dnsServers": { + "value": "[parameters('dnsServers')]" }, - "description": { - "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": { + "value": "[parameters('roleAssignments')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "272838238520810437" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface." + }, + "definitions": { + "networkInterfaceIPConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the IP configuration." + } + }, + "privateIPAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. The private IP address allocation method." + } + }, + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address." + } + }, + "publicIPAddressResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the public IP address." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet." + } + }, + "loadBalancerBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/backendAddressPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of load balancer backend address pools." + } + }, + "loadBalancerInboundNatRules": { + "type": "array", + "items": { + "$ref": "#/definitions/inboundNatRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of references of LoadBalancerInboundNatRules." + } + }, + "applicationSecurityGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationSecurityGroupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the IP configuration is included." + } + }, + "applicationGatewayBackendAddressPools": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationGatewayBackendAddressPoolsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Application Gateway Backend Address Pools." + } + }, + "gatewayLoadBalancer": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. The reference to gateway load balancer frontend IP." + } + }, + "privateIPAddressVersion": { + "type": "string", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether the specific IP configuration is IPv4 or IPv6." + } + }, + "virtualNetworkTaps": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkTapType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The reference to Virtual Network Taps." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The resource ID of the deployed resource." + } + }, + "backendAddressPoolType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backend address pool." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backend address pool." + } + }, + "applicationSecurityGroupType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the application security group." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the application security group." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application security group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the application security group." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application security group." + } + }, + "applicationGatewayBackendAddressPoolsType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the backend address pool." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the backend address pool that is unique within an Application Gateway." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. IP address of the backend address." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN of the backend address." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Backend addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the application gateway backend address pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the application gateway backend address pool." + } + }, + "subResourceType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the sub resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the sub resource." + } + }, + "inboundNatRuleType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the inbound NAT rule." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the resource that is unique within the set of inbound NAT rules used by the load balancer. This name can be used to access the resource." + } + }, + "properties": { + "type": "object", + "properties": { + "backendAddressPool": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to backendAddressPool resource." + } + }, + "backendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port used for the internal endpoint. Acceptable values range from 1 to 65535." + } + }, + "enableFloatingIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfiguration": { + "$ref": "#/definitions/subResourceType", + "nullable": true, + "metadata": { + "description": "Optional. A reference to frontend IP addresses." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Acceptable values range from 1 to 65534." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "nullable": true, + "metadata": { + "description": "Optional. The reference to the transport protocol used by the load balancing rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the inbound NAT rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the inbound NAT rule." + } + }, + "virtualNetworkTapType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the virtual network tap." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the virtual network tap." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Properties of the virtual network tap." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the virtual network tap." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the virtual network tap." + } + }, + "networkInterfaceIPConfigurationOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP configuration." + } + }, + "privateIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The private IP address." + } + }, + "publicIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The public IP address." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network interface IP configuration output." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, "parameters": { - "scope": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/networkInterfaces@2024-07-01#properties/tags" + }, + "description": "Optional. Resource tags." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationType" + }, + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, "metadata": { - "description": "Required. The scope to deploy the role assignment to." + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "publicIp": { + "copy": { + "name": "publicIp", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null())))]", + "existing": true, + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "resourceGroup": "[split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), ''), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.5.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), format('ipconfig{0}', padLeft(add(copyIndex('ipConfigurations'), 1), 2, '0')))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod')]", + "privateIPAddress": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress')]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), null())), createObject('id', tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId')), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools')]", + "applicationSecurityGroups": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups')]", + "applicationGatewayBackendAddressPools": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools')]", + "gatewayLoadBalancer": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer')]", + "loadBalancerInboundNatRules": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules')]", + "privateIPAddressVersion": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion')]", + "virtualNetworkTaps": "[tryGet(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps')]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" } }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "networkInterface" + ] }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] }, - "principalType": { + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" }, - "description": { + "resourceId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The description of the role assignment." - } + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" }, - "condition": { + "resourceGroupName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" - } + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" }, - "conditionVersion": { + "location": { "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", "metadata": { - "description": "Optional. Version of the condition." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2024-05-01', 'full').location]" }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[parameters('scope')]", - "name": "[parameters('name')]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "principalId": "[parameters('principalId')]", - "description": "[parameters('description')]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + "description": "The list of IP configurations of the network interface." + }, + "copy": { + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[reference('networkInterface').ipConfigurations[copyIndex()].name]", + "privateIP": "[coalesce(tryGet(reference('networkInterface').ipConfigurations[copyIndex()].properties, 'privateIPAddress'), '')]", + "publicIP": "[if(and(contains(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), not(equals(tryGet(parameters('ipConfigurations')[copyIndex()], 'publicIPAddressResourceId'), null()))), coalesce(reference(format('publicIp[{0}]', copyIndex())).ipAddress, ''), '')]" + } } } - ] + } } }, "dependsOn": [ - "fileShare" + "networkInterface_publicIPAddresses" ] } }, "outputs": { "name": { "type": "string", - "metadata": { - "description": "The name of the deployed file share." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "fileServices", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_queueServices": { - "condition": "[not(empty(parameters('queueServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" - }, - "queues": { - "value": "[tryGet(parameters('queueServices'), 'queues')]" - }, - "corsRules": { - "value": "[tryGet(parameters('queueServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9644461291744477521" - }, - "name": "Storage Account Queue Services", - "description": "This module deploys a Storage Account Queue Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "queueType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the queue." - } - }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. Metadata to set on the queue." - }, - "nullable": true - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a queue." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "queues": { - "type": "array", - "items": { - "$ref": "#/definitions/queueType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Queues to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "queueServices": { - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" - } - }, - "queueServices_diagnosticSettings": { - "copy": { - "name": "queueServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "metadata": { + "description": "The name of the network interface." + }, + "value": "[reference('networkInterface').outputs.name.value]" + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/networkInterfaceIPConfigurationOutputType" + }, + "metadata": { + "description": "The list of IP configurations of the network interface." + }, + "value": "[reference('networkInterface').outputs.ipConfigurations.value]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "queueServices" - ] + } + } }, - "queueServices_queues": { - "copy": { - "name": "queueServices_queues", - "count": "[length(coalesce(parameters('queues'), createArray()))]" - }, + "vm_domainJoinExtension": { + "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "virtualMachineName": { + "value": "[parameters('name')]" }, "name": { - "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'name'), 'DomainJoin')]" }, - "metadata": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + "location": { + "value": "[parameters('location')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + "publisher": { + "value": "Microsoft.Compute" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'settings'), createObject('Name', tryGet(parameters('extensionDomainJoinConfig'), 'domainName'), 'OUPath', tryGet(parameters('extensionDomainJoinConfig'), 'ouPath'), 'User', tryGet(parameters('extensionDomainJoinConfig'), 'user'), 'Restart', tryGet(parameters('extensionDomainJoinConfig'), 'restart'), 'Options', tryGet(parameters('extensionDomainJoinConfig'), 'options')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } } }, "template": { @@ -34483,719 +17404,455 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "12812824360066955039" + "templateHash": "3581830278162851734" }, - "name": "Storage Account Queues", - "description": "This module deploys a Storage Account Queue." - }, - "definitions": { - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, "parameters": { - "storageAccountName": { + "virtualMachineName": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." } }, "name": { "type": "string", "metadata": { - "description": "Required. The name of the storage queue to deploy." + "description": "Required. The name of the virtual machine extension." } }, - "metadata": { - "type": "object", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" - }, - "description": "Optional. A name-value pair that represents queue metadata." - }, - "defaultValue": {} + "description": "Optional. The location the extension is deployed to." + } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "publisher": { + "type": "string", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Required. The name of the extension handler publisher." } }, - "enableTelemetry": { + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", - "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", - "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "storageAccount::queueServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } }, - "queue": { - "type": "Microsoft.Storage/storageAccounts/queueServices/queues", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]" + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." } }, - "queue_roleAssignments": { - "copy": { - "name": "queue_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "queue" - ] - } - }, - "outputs": { - "name": { - "type": "string", + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", "metadata": { - "description": "The name of the deployed queue." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "value": "[parameters('name')]" + "nullable": true }, - "resourceId": { - "type": "string", + "protectedSettingsFromKeyVault": { + "type": "object", "metadata": { - "description": "The resource ID of the deployed queue." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + "nullable": true }, - "resourceGroupName": { - "type": "string", + "provisionAfterExtensions": { + "type": "array", "metadata": { - "description": "The resource group of the deployed queue." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." }, - "value": "[resourceGroup().name]" + "nullable": true } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed queue service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed queue service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed queue service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_tableServices": { - "condition": "[not(empty(parameters('tableServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" - }, - "tables": { - "value": "[tryGet(parameters('tableServices'), 'tables')]" - }, - "corsRules": { - "value": "[tryGet(parameters('tableServices'), 'corsRules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "10320403358700650147" - }, - "name": "Storage Account Table Services", - "description": "This module deploys a Storage Account Table Service." - }, - "definitions": { - "corsRuleType": { - "type": "object", - "properties": { - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of headers allowed to be part of the cross-origin request." - } - }, - "allowedMethods": { - "type": "array", - "allowedValues": [ - "CONNECT", - "DELETE", - "GET", - "HEAD", - "MERGE", - "OPTIONS", - "PATCH", - "POST", - "PUT", - "TRACE" - ], - "metadata": { - "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." - } - }, - "exposedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of response headers to expose to CORS clients." - } - }, - "maxAgeInSeconds": { - "type": "int", - "metadata": { - "description": "Required. The number of seconds that the client/browser should cache a preflight response." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cors rule." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "dependsOn": [ + "vm" + ] }, - "roleAssignmentType": { - "type": "object", + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'name'), 'AADLogin')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": "[if(not(empty(variables('filteredAadJoinSettings'))), createObject('value', variables('filteredAadJoinSettings')), createObject('value', null()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Tables to create." - } - }, - "corsRules": { - "type": "array", - "items": { - "$ref": "#/definitions/corsRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "name": "default", - "enableReferencedModulesTelemetry": false - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" - }, - "tableServices": { - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", - "properties": { - "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" - } - }, - "tableServices_diagnosticSettings": { - "copy": { - "name": "tableServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } }, "dependsOn": [ - "tableServices" + "vm", + "vm_domainJoinExtension" ] }, - "tableServices_tables": { - "copy": { - "name": "tableServices_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, + "vm_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'name'), 'MicrosoftAntiMalware')]" }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "location": { + "value": "[parameters('location')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + "publisher": { + "value": "Microsoft.Azure.Security" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" } }, "template": { @@ -35206,585 +17863,458 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "11362260974696477885" + "templateHash": "3581830278162851734" }, - "name": "Storage Account Table", - "description": "This module deploys a Storage Account Table." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, - "definitions": { - "roleAssignmentType": { + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" } } }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] + }, + "vm_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'name'), 'AzureMonitorAgent')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, "parameters": { - "storageAccountName": { + "virtualMachineName": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Required. The name of the virtual machine extension." } }, - "name": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Name of the table." + "description": "Optional. The location the extension is deployed to." } }, - "enableTelemetry": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", - "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "storageAccount::tableServices": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." } }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-06-01", - "name": "[parameters('storageAccountName')]" + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } }, - "table": { - "type": "Microsoft.Storage/storageAccounts/tableServices/tables", - "apiVersion": "2025-06-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } }, - "table_roleAssignments": { - "copy": { - "name": "table_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." }, - "dependsOn": [ - "table" - ] + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed table." + "description": "The name of the extension." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed table." + "description": "The resource ID of the extension." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed table." + "description": "The name of the Resource Group the extension was created in." }, "value": "[resourceGroup().name]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed table service." - }, - "value": "[variables('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed table service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed table service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "13227497656004178962" - } - }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_objectReplicationPolicies": { - "copy": { - "name": "storageAccount_objectReplicationPolicies", - "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "destinationAccountResourceId": { - "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" - }, - "enableMetrics": { - "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" - }, - "rules": { - "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "1894366578172550759" - }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." - }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } }, - "minCreationTime": { + "location": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." } } }, - "metadata": { - "description": "The type of an object replication policy rule.", - "__bicep_imported_from!": { - "sourceTemplate": "policy/main.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the policy." - } - }, - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. The name of the parent Storage Account." - } - }, - "destinationAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." - } - }, - "enableMetrics": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, - "metadata": { - "description": "Required. Rules for the object replication policy." - } - } - }, - "variables": { - "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", - "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", - "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", - "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" + "dependsOn": [ + "vm", + "vm_microsoftAntiMalwareExtension" + ] }, - "destinationPolicy": { + "vm_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", - "subscriptionId": "[variables('destAccountSubscription')]", - "resourceGroup": "[variables('destAccountResourceGroupName')]", + "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[coalesce(parameters('name'), 'default')]" + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'name'), 'DependencyAgent')]" }, - "storageAccountName": { - "value": "[variables('destAccountName')]" + "location": { + "value": "[parameters('location')]" }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" }, - "rules": { - "value": "[parameters('rules')]" + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, + "settings": { + "value": { + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" } }, "template": { @@ -35795,213 +18325,223 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "14995722372031126283" + "templateHash": "3581830278162851734" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } - }, - "minCreationTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy rule." + "description": "Optional. The location the extension is deployed to." } - } - }, - "parameters": { - "name": { + }, + "publisher": { "type": "string", "metadata": { - "description": "Required. Name of the policy." + "description": "Required. The name of the extension handler publisher." } }, - "storageAccountName": { + "type": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." } }, - "sourceStorageAccountResourceId": { + "typeHandlerVersion": { "type": "string", "metadata": { - "description": "Required. Resource ID of the source storage account for replication." + "description": "Required. Specifies the version of the script handler." } }, - "destinationAccountResourceId": { + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." } }, - "enableMetrics": { - "type": "bool", + "settings": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." + "description": "Optional. Any object that contains the extension specific settings." } }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, "metadata": { - "description": "Required. Rules for the object replication policy." + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true } }, "resources": { - "storageAccount": { + "virtualMachine": { "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" - } - } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" - }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" } } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "Resource group name of the provisioned resources." + "description": "The name of the extension." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, - "objectReplicationPolicyId": { + "resourceId": { "type": "string", "metadata": { - "description": "Resource ID of the created Object Replication Policy." + "description": "The resource ID of the extension." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" }, - "policyId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Policy ID of the created Object Replication Policy." + "description": "The name of the Resource Group the extension was created in." }, - "value": "[reference('objectReplicationPolicy').policyId]" + "value": "[resourceGroup().name]" }, - "rules": { - "type": "array", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true - }, - "description": "Rules created Object Replication Policy." + "description": "The location the resource was deployed into." }, - "value": "[reference('objectReplicationPolicy').rules]" + "value": "[reference('extension', '2024-11-01', 'full').location]" } } } - } + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] }, - "sourcePolicy": { + "vm_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", + "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, "name": { - "value": "[reference('destinationPolicy').outputs.policyId.value]" + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'name'), 'NetworkWatcherAgent')]" }, - "storageAccountName": { - "value": "[parameters('storageAccountName')]" + "location": { + "value": "[parameters('location')]" }, - "sourceStorageAccountResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" }, - "destinationAccountResourceId": { - "value": "[parameters('destinationAccountResourceId')]" + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" }, - "enableMetrics": { - "value": "[parameters('enableMetrics')]" + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" }, - "rules": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('rules'))]", - "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" - } - ] + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" } }, "template": { @@ -36012,1534 +18552,2433 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "14995722372031126283" + "templateHash": "3581830278162851734" }, - "name": "Storage Account Object Replication Policy", - "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." }, - "definitions": { - "objectReplicationPolicyRuleType": { - "type": "object", - "properties": { - "ruleId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." - } - }, - "containerName": { - "type": "string", - "metadata": { - "description": "Required. The name of the source container." - } - }, - "destinationContainerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." - } - }, - "filters": { - "type": "object", - "properties": { - "prefixMatch": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The prefix to match for the replication policy rule." - } - }, - "minCreationTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The minimum creation time to match for the replication policy rule." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The filters for the object replication policy rule." - } - } - }, + "parameters": { + "virtualMachineName": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type of an object replication policy rule." + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." } - } - }, - "parameters": { + }, "name": { "type": "string", "metadata": { - "description": "Required. Name of the policy." + "description": "Required. The name of the virtual machine extension." } }, - "storageAccountName": { + "location": { "type": "string", - "maxLength": 24, + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The name of the Storage Account on which to create the policy." + "description": "Optional. The location the extension is deployed to." } }, - "sourceStorageAccountResourceId": { + "publisher": { "type": "string", "metadata": { - "description": "Required. Resource ID of the source storage account for replication." + "description": "Required. The name of the extension handler publisher." } }, - "destinationAccountResourceId": { + "type": { "type": "string", "metadata": { - "description": "Required. Resource ID of the destination storage account for replication." + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." } }, - "enableMetrics": { + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Whether metrics are enabled for the object replication policy." + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." } }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/objectReplicationPolicyRuleType" - }, + "settings": { + "type": "object", + "nullable": true, "metadata": { - "description": "Required. Rules for the object replication policy." + "description": "Optional. Any object that contains the extension specific settings." } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", - "name": "[parameters('storageAccountName')]" }, - "objectReplicationPolicy": { - "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "rules", - "count": "[length(parameters('rules'))]", - "input": { - "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", - "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", - "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", - "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" - } - } - ], - "destinationAccount": "[parameters('destinationAccountResourceId')]", - "metrics": { - "enabled": "[coalesce(parameters('enableMetrics'), false())]" - }, - "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } }, - "objectReplicationPolicyId": { - "type": "string", + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", "metadata": { - "description": "Resource ID of the created Object Replication Policy." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + "nullable": true }, - "policyId": { - "type": "string", + "protectedSettingsFromKeyVault": { + "type": "object", "metadata": { - "description": "Policy ID of the created Object Replication Policy." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." }, - "value": "[reference('objectReplicationPolicy').policyId]" + "nullable": true }, - "rules": { + "provisionAfterExtensions": { "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", - "output": true + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" }, - "description": "Rules created Object Replication Policy." + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." }, - "value": "[reference('objectReplicationPolicy').rules]" + "nullable": true } - } - } - }, - "dependsOn": [ - "destinationPolicy" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "Resource group name of the provisioned resources." - }, - "value": "[resourceGroup().name]" - }, - "objectReplicationPolicyId": { - "type": "string", - "metadata": { - "description": "Resource ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Policy ID of the created Object Replication Policy in the source account." - }, - "value": "[reference('sourcePolicy').outputs.policyId.value]" - } - } - } - }, - "dependsOn": [ - "storageAccount", - "storageAccount_blobServices" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2025-06-01', 'full').location]" - }, - "serviceEndpoints": { - "type": "object", - "metadata": { - "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." - }, - "value": "[reference('storageAccount').primaryEndpoints]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the Storage Account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "primaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The primary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" - }, - "secondaryAccessKey": { - "type": "securestring", - "metadata": { - "description": "The secondary access key of the storage account." - }, - "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" - }, - "primaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The primary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" - }, - "secondaryConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary connection string of the storage account." - }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", - "virtualNetwork" - ] - }, - "avmAiServices": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "projectName": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "projectDescription": { - "value": "[format('proj-{0}', variables('solutionSuffix'))]" - }, - "existingFoundryProjectResourceId": { - "value": "[variables('existingProjectResourceId')]" - }, - "location": { - "value": "[parameters('azureAiServiceLocation')]" - }, - "sku": { - "value": "S0" - }, - "allowProjectManagement": { - "value": true - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "kind": { - "value": "AIServices" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('azureAiServiceLocation')]" - } - }, - "customSubDomainName": { - "value": "[format('aif-{0}', variables('solutionSuffix'))]" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services OpenAI User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Azure AI Developer", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]", - "roleDefinitionIdOrName": "Cognitive Services User", - "principalType": "ServicePrincipal" - } - ] - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" - } - }, - "disableLocalAuth": { - "value": true - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "deployments": { - "value": [ - { - "name": "[parameters('gptModelName')]", - "model": { - "format": "OpenAI", - "name": "[parameters('gptModelName')]", - "version": "[parameters('gptModelVersion')]" - }, - "sku": { - "name": "[parameters('deploymentType')]", - "capacity": "[parameters('gptDeploymentCapacity')]" - }, - "raiPolicyName": "Microsoft.Default" - } - ] - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "18336251851332975005" - }, - "name": "Cognitive Services", - "description": "This module deploys a Cognitive Service." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "dependsOn": [ + "vm", + "vm_dependencyAgentExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'name'), 'DesiredStateConfiguration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + }, + "dependsOn": [ + "vm", + "vm_networkWatcherAgentExtension" + ] }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + "vm_customScriptExtension": { + "condition": "[not(empty(parameters('extensionCustomScriptConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'name'), 'CustomScriptExtension')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'forceUpdateTag')]" + }, + "provisionAfterExtensions": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'provisionAfterExtensions')]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettingsFromKeyVault": { + "value": "[tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettingsFromKeyVault')]" + }, + "settings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'settings'), 'fileUris'))), createObject('fileUris', tryGet(parameters('extensionCustomScriptConfig'), 'settings', 'fileUris')), createObject())))]" + }, + "protectedSettings": { + "value": "[shallowMerge(createArray(if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'commandToExecute'))), createObject('commandToExecute', tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'commandToExecute')), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountName'))), createObject('storageAccountName', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountName), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'storageAccountKey'))), createObject('storageAccountKey', parameters('extensionCustomScriptConfig').protectedSettings.storageAccountKey), createObject()), if(not(empty(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'fileUris'))), createObject('fileUris', parameters('extensionCustomScriptConfig').protectedSettings.fileUris), createObject()), if(not(equals(tryGet(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), 'managedIdentityResourceId'), null())), createObject('managedIdentity', if(not(empty(tryGet(parameters('extensionCustomScriptConfig').protectedSettings, 'managedIdentityResourceId'))), createObject('clientId', reference('cseIdentity').clientId), createObject())), createObject())))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/project.bicep" - } - } - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "dependsOn": [ + "cseIdentity", + "vm" + ] + }, + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'name'), 'AzureDiskEncryption')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "dependsOn": [ + "vm", + "vm_customScriptExtension" + ] + }, + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'name'), 'NvidiaGpuDriverWindows')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] + }, + "vm_hostPoolRegistrationExtension": { + "condition": "[parameters('extensionHostPoolRegistration').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'name'), 'HostPoolRegistration')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.PowerShell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", + "properties": { + "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", + "aadJoin": true + } + } + }, + "protectedSettings": { + "value": { + "properties": { + "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]" + } + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "dependsOn": [ + "vm", + "vm_nvidiaGpuDriverWindowsExtension" + ] + }, + "vm_azureGuestConfigurationExtension": { + "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": "[if(coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'name'), equals(parameters('osType'), 'Windows')), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.GuestConfiguration" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, + "protectedSettings": { + "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "3581830278162851734" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "protectedSettingsFromKeyVault": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/protectedSettingsFromKeyVault" + }, + "description": "Optional. The extensions protected settings that are passed by reference, and consumed from key vault." + }, + "nullable": true + }, + "provisionAfterExtensions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Compute/virtualMachines/extensions@2024-11-01#properties/properties/properties/provisionAfterExtensions" + }, + "description": "Optional. Collection of extension names after which this extension needs to be provisioned." + }, + "nullable": true + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "settings": "[parameters('settings')]", + "protectedSettings": "[parameters('protectedSettings')]", + "suppressFailures": "[parameters('supressFailures')]", + "protectedSettingsFromKeyVault": "[parameters('protectedSettingsFromKeyVault')]", + "provisionAfterExtensions": "[parameters('provisionAfterExtensions')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2024-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_hostPoolRegistrationExtension" + ] + }, + "vm_backup": { + "condition": "[not(empty(parameters('backupVaultName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('backupVaultResourceGroup')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyId": { + "value": "[resourceId(parameters('backupVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + }, + "protectedItemType": { + "value": "Microsoft.Compute/virtualMachines" + }, + "protectionContainerName": { + "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "recoveryVaultName": { + "value": "[parameters('backupVaultName')]" + }, + "sourceResourceId": { + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17448691641471706096" + }, + "name": "Recovery Service Vaults Protection Container Protected Item", + "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "protectionContainerName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + } + }, + "recoveryVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "protectedItemType": { + "type": "string", + "allowedValues": [ + "AzureFileShareProtectedItem", + "AzureVmWorkloadSAPAseDatabase", + "AzureVmWorkloadSAPHanaDatabase", + "AzureVmWorkloadSQLDatabase", + "DPMProtectedItem", + "GenericProtectedItem", + "MabFileFolderProtectedItem", + "Microsoft.ClassicCompute/virtualMachines", + "Microsoft.Compute/virtualMachines", + "Microsoft.Sql/servers/databases" + ], + "metadata": { + "description": "Required. The backup item type." + } + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Required. ID of the backup policy with which this item is backed up." + } + }, + "sourceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource to back up." + } + } + }, + "resources": [ + { + "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", + "apiVersion": "2025-02-01", + "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "protectedItemType": "[parameters('protectedItemType')]", + "policyId": "[parameters('policyId')]", + "sourceResourceId": "[parameters('sourceResourceId')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the protected item was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the protected item." + }, + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The Name of the protected item." + }, + "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + } }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VM." + }, + "value": "[parameters('name')]" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2024-07-01', 'full').location]" + }, + "nicConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/nicConfigurationOutputType" + }, + "metadata": { + "description": "The list of NIC configurations of the virtual machine." + }, + "copy": { + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "name": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.name.value]", + "ipConfigurations": "[reference(format('vm_nic[{0}]', copyIndex())).outputs.ipConfigurations.value]" + } + } + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } } }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "projectName": { - "type": "string", - "metadata": { - "description": "Optional: Name for the project which needs to be created." - } - }, - "projectDescription": { - "type": "string", - "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "" - }, - "kind": { - "type": "string", - "allowedValues": [ - "AIServices", - "AnomalyDetector", - "CognitiveServices", - "ComputerVision", - "ContentModerator", - "ContentSafety", - "ConversationalLanguageUnderstanding", - "CustomVision.Prediction", - "CustomVision.Training", - "Face", - "FormRecognizer", - "HealthInsights", - "ImmersiveReader", - "Internal.AllInOne", - "LUIS", - "LUIS.Authoring", - "LanguageAuthoring", - "MetricsAdvisor", - "OpenAI", - "Personalizer", - "QnAMaker.v2", - "SpeechServices", - "TextAnalytics", - "TextTranslation" - ], - "metadata": { - "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "sku": { + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } + "description": "Resource ID of the virtual machine." + }, + "value": "[reference('virtualMachine').outputs.resourceId.value]" }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" + "description": "Name of the virtual machine." }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." + "value": "[reference('virtualMachine').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.maintenance-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.data-collection-rule.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.maintenance-configuration.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('mc-{0}', variables('jumpboxVmName'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionProperties": { + "value": { + "InGuestPatchMode": "User" + } + }, + "maintenanceScope": { + "value": "InGuestPatch" + }, + "maintenanceWindow": { + "value": { + "startDateTime": "2024-06-16 00:00", + "duration": "03:55", + "timeZone": "W. Europe Standard Time", + "recurEvery": "1Day" + } + }, + "visibility": { + "value": "Custom" + }, + "installPatches": { + "value": { + "rebootSetting": "IfRequired", + "windowsParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] + }, + "linuxParameters": { + "classificationsToInclude": [ + "Critical", + "Security" + ] } - }, - "publicNetworkAccess": { + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "17869572276338216144" + } + }, + "parameters": { + "name": { "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + "description": "Name of the maintenance configuration." } }, - "customSubDomainName": { + "location": { "type": "string", - "nullable": true, "metadata": { - "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + "description": "Azure region for the resource." } }, - "networkAcls": { + "tags": { "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A collection of rules governing the accessibility from specific network locations." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "defaultValue": {}, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Tags to apply to the resource." } }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "tags": { + "extensionProperties": { "type": "object", - "nullable": true, + "defaultValue": {}, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Extension properties for the maintenance configuration." } }, - "allowedFqdnList": { - "type": "array", - "nullable": true, + "maintenanceScope": { + "type": "string", "metadata": { - "description": "Optional. List of allowed FQDN." + "description": "Maintenance scope for the configuration." } }, - "apiProperties": { + "maintenanceWindow": { "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The API properties for special APIs." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + "description": "Maintenance window configuration." } }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "nullable": true, + "visibility": { + "type": "string", + "defaultValue": "Custom", "metadata": { - "description": "Optional. The customer managed key definition." + "description": "Visibility of the maintenance configuration." } }, - "dynamicThrottlingEnabled": { - "type": "bool", - "defaultValue": false, + "installPatches": { + "type": "object", "metadata": { - "description": "Optional. The flag to enable dynamic throttling." + "description": "Install patches configuration." } - }, - "migrationToken": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. Resource migration token." + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.maintenance.maintenance-configuration.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionProperties": { + "value": "[parameters('extensionProperties')]" + }, + "maintenanceScope": { + "value": "[parameters('maintenanceScope')]" + }, + "maintenanceWindow": { + "value": "[parameters('maintenanceWindow')]" + }, + "visibility": { + "value": "[parameters('visibility')]" + }, + "installPatches": { + "value": "[parameters('installPatches')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14895287194406877557" + }, + "name": "Maintenance Configurations", + "description": "This module deploys a Maintenance Configuration." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Maintenance Configuration Name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "extensionProperties": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/extensionProperties" + }, + "description": "Optional. Gets or sets extensionProperties of the maintenanceConfiguration." + }, + "defaultValue": {} + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "maintenanceScope": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceScope" + }, + "description": "Optional. Gets or sets maintenanceScope of the configuration." + }, + "defaultValue": "Host" + }, + "maintenanceWindow": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/maintenanceWindow" + }, + "description": "Optional. Definition of a MaintenanceWindow." + }, + "defaultValue": {} + }, + "namespace": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Gets or sets namespace of the resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/tags" + }, + "description": "Optional. Gets or sets tags of the resource." + }, + "nullable": true + }, + "visibility": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/visibility" + }, + "description": "Optional. Gets or sets the visibility of the configuration. The default value is 'Custom'." + }, + "nullable": true + }, + "installPatches": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01#properties/properties/properties/installPatches" + }, + "description": "Optional. Configuration settings for VM guest patching with Azure Update Manager." + }, + "defaultValue": {} + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Scheduled Patching Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cd08ab90-6b14-449c-ad9a-8f8e549482c6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.maintenance-maintenanceconfiguration.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "maintenanceConfiguration": { + "type": "Microsoft.Maintenance/maintenanceConfigurations", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "extensionProperties": "[parameters('extensionProperties')]", + "maintenanceScope": "[parameters('maintenanceScope')]", + "maintenanceWindow": "[parameters('maintenanceWindow')]", + "namespace": "[parameters('namespace')]", + "visibility": "[parameters('visibility')]", + "installPatches": "[if(equals(parameters('maintenanceScope'), 'InGuestPatch'), parameters('installPatches'), null())]" + } + }, + "maintenanceConfiguration_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + }, + "maintenanceConfiguration_roleAssignments": { + "copy": { + "name": "maintenanceConfiguration_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "maintenanceConfiguration" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Maintenance Configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Maintenance Configuration." + }, + "value": "[resourceId('Microsoft.Maintenance/maintenanceConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Maintenance Configuration was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the Maintenance Configuration was created in." + }, + "value": "[reference('maintenanceConfiguration', '2023-04-01', 'full').location]" + } + } + } } - }, - "restore": { - "type": "bool", - "defaultValue": false, + } + ], + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." - } + "description": "Resource ID of the maintenance configuration." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.maintenance.maintenance-configuration.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "restrictOutboundNetworkAccess": { - "type": "bool", - "defaultValue": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. Restrict outbound network access." + "description": "Name of the maintenance configuration." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.maintenance.maintenance-configuration.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + { + "copy": { + "name": "avmPrivateDnsZones", + "count": "[length(variables('privateDnsZones'))]", + "mode": "serial", + "batchSize": 5 + }, + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), copyIndex()), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZones')[copyIndex()]]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "virtualNetworkLinks": { + "value": [ + { + "virtualNetworkResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" } - }, - "userOwnedStorage": { - "type": "array", - "nullable": true, + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12448195195174935873" + } + }, + "parameters": { + "name": { + "type": "string", "metadata": { - "description": "Optional. The storage accounts for this resource." + "description": "Name of the private DNS zone." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Tags to apply to the resource." } }, "enableTelemetry": { @@ -37549,173 +20988,36 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "deployments": { + "virtualNetworkLinks": { "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "allowProjectManagement": { - "type": "bool", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. Enable/Disable project management feature for AI Foundry." + "description": "Optional. Virtual network link configurations for the private DNS zone." } } }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", - "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2025-01-31-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "cognitiveServiceNew": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]", - "kind": "[parameters('kind')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "properties": { - "allowProjectManagement": "[parameters('allowProjectManagement')]", - "customSubDomainName": "[parameters('customSubDomainName')]", - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", - "allowedFqdnList": "[parameters('allowedFqdnList')]", - "apiProperties": "[parameters('apiProperties')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", - "migrationToken": "[parameters('migrationToken')]", - "restore": "[parameters('restore')]", - "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", - "userOwnedStorage": "[parameters('userOwnedStorage')]", - "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "cognitiveServiceExisting": { - "condition": "[variables('useExistingService')]", - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", - "name": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "cognitive_service_dependencies": { - "condition": "[not(variables('useExistingService'))]", + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", + "name": "[take(format('avm.res.network.private-dns-zone.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, "name": { "value": "[parameters('name')]" }, - "location": { - "value": "[parameters('location')]" - }, - "deployments": { - "value": "[parameters('deployments')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" - }, - "sku": { - "value": "[parameters('sku')]" - }, "tags": { "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "virtualNetworkLinks": { + "value": "[parameters('virtualNetworkLinks')]" } }, "template": { @@ -37725,1097 +21027,2308 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8883353547455396972" - } + "version": "0.41.2.15936", + "templateHash": "18337341331267624582" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone." }, "definitions": { - "privateEndpointOutputType": { + "aType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "Required. The name of the record." } }, - "resourceId": { - "type": "string", + "metadata": { + "type": "object", "metadata": { - "description": "The resource ID of the private endpoint." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true }, - "groupId": { - "type": "string", + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "Optional. The TTL of the record." } }, - "customDnsConfigs": { + "roleAssignments": { "type": "array", "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, "metadata": { - "description": "The custom DNS configurations of the private endpoint." + "description": "Optional. Array of role assignments to create." } }, - "networkInterfaceResourceIds": { + "aRecords": { "type": "array", - "items": { - "type": "string" - }, "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "The type for the private endpoint output." + "description": "The type for the A record." } }, - "deploymentType": { + "aaaaType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." + "description": "Required. The name of the record." } }, - "model": { + "metadata": { "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aaaaRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } + "description": "Optional. The list of AAAA records in the record set." }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the AAAA record." + } + }, + "cnameType": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." + "description": "Required. The name of the record." } }, - "sku": { + "metadata": { "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } + "description": "Optional. The metadata of the record." }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The resource model definition representing SKU." + "description": "Optional. The TTL of the record." } }, - "raiPolicyName": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The name of RAI policy." + "description": "Optional. Array of role assignments to create." } }, - "versionUpgradeOption": { + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. The CNAME record in the record set." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the CNAME record." + } + }, + "mxType": { + "type": "object", + "properties": { + "name": { "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The version upgrade option." + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." + "description": "The type for the MX record." } }, - "endpointType": { + "ptrType": { "type": "object", "properties": { "name": { "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Type of the endpoint." + "description": "Optional. The TTL of the record." } }, - "endpoint": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "The endpoint URI." + "description": "Optional. Array of role assignments to create." } + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." + "description": "The type for the PTR record." } }, - "secretsExportConfigurationType": { + "soaType": { "type": "object", "properties": { - "keyVaultResourceId": { + "name": { "type": "string", "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + "description": "Required. The name of the record." } }, - "accessKey1Name": { - "type": "string", + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." + "description": "Optional. The TTL of the record." } }, - "accessKey2Name": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." + "description": "Optional. Array of role assignments to create." } + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. The SOA record in the record set." + }, + "nullable": true } }, "metadata": { "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." + "description": "The type for the SOA record." } }, - "_1.privateEndpointCustomDnsConfigType": { + "srvType": { "type": "object", "properties": { - "fqdn": { + "name": { "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. The TTL of the record." } }, - "ipAddresses": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. Array of role assignments to create." } + }, + "srvRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for the SRV record." } }, - "_1.privateEndpointIpConfigurationType": { + "txtType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. The name of the record." } }, - "properties": { + "metadata": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } + "description": "Optional. The metadata of the record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "txtRecords": { + "type": "array", "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for the TXT record." } }, - "_1.privateEndpointPrivateDnsZoneGroupType": { + "virtualNetworkLinkType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, + "minLength": 1, + "maxLength": 80, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. The resource name." } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the virtual network to link." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Region where the resource lives." + } + }, + "registrationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Resource tags." }, + "nullable": true + }, + "resolutionPolicy": { + "type": "string", + "allowedValues": [ + "Default", + "NxDomainRedirect" + ], + "nullable": true, "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + "description": "Optional. The resolution type of the private-dns-zone fallback machanism." } } }, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "__bicep_export!": true, + "description": "The type for the virtual network link." } }, - "_1.secretSetOutputType": { + "lockType": { "type": "object", "properties": { - "secretResourceId": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "The resourceId of the exported secret." + "description": "Optional. Specify the name of lock." } }, - "secretUri": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, "metadata": { - "description": "The secret URI of the exported secret." + "description": "Optional. Specify the type of lock." } }, - "secretUriWithVersion": { + "notes": { "type": "string", + "nullable": true, "metadata": { - "description": "The secret URI with version of the exported secret." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } }, - "aiProjectOutputType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the AI project." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "resourceId": { + "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the AI project." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "apiEndpoint": { + "principalId": { "type": "string", "metadata": { - "description": "Required. API endpoint for the AI project." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "Output type representing AI project information.", + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } }, - "diagnosticSettingFullType": { + "a": { + "type": "array", + "items": { + "$ref": "#/definitions/aType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of A records." + } + }, + "aaaa": { + "type": "array", + "items": { + "$ref": "#/definitions/aaaaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of AAAA records." + } + }, + "cname": { + "type": "array", + "items": { + "$ref": "#/definitions/cnameType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of CNAME records." + } + }, + "mx": { + "type": "array", + "items": { + "$ref": "#/definitions/mxType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of MX records." + } + }, + "ptr": { + "type": "array", + "items": { + "$ref": "#/definitions/ptrType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of PTR records." + } + }, + "soa": { + "type": "array", + "items": { + "$ref": "#/definitions/soaType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SOA records." + } + }, + "srv": { + "type": "array", + "items": { + "$ref": "#/definitions/srvType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of SRV records." + } + }, + "txt": { + "type": "array", + "items": { + "$ref": "#/definitions/txtType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of TXT records." + } + }, + "virtualNetworkLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/virtualNetworkLinkType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.8.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "name": { - "type": "string", - "nullable": true, + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_roleAssignments": { + "copy": { + "name": "privateDnsZone_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_A": { + "copy": { + "name": "privateDnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" + }, + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" + }, "metadata": { - "description": "Optional. The name of the diagnostic setting." + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7372385900111002873" + }, + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the A record." + } + }, + "aRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/aRecords" + }, + "description": "Optional. The list of A records in the record set." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/A@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonea.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } } } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed A record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed A record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed A record." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "dependsOn": [ + "privateDnsZone" + ] }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } + "privateDnsZone_AAAA": { + "copy": { + "name": "privateDnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + "name": { + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "tags": { - "type": "object", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14405855828972373002" + }, + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the AAAA record." + } + }, + "aaaaRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/aaaaRecords" + }, + "description": "Optional. The list of AAAA records in the record set." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/AAAA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneaaaa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AAAA record." + }, + "value": "[parameters('name')]" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed AAAA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed AAAA record." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "dependsOn": [ + "privateDnsZone" + ] }, - "roleAssignmentType": { - "type": "object", + "privateDnsZone_CNAME": { + "copy": { + "name": "privateDnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" + }, + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" + }, "metadata": { - "description": "Optional. Version of the condition." + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "sku": { - "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "projectName": { - "type": "string", - "metadata": { - "description": "Optional: Name for the project which needs to be created." - } - }, - "projectDescription": { - "type": "string", - "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13818627461335065928" + }, + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CNAME record." + } + }, + "cnameRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/cnameRecord" + }, + "description": "Optional. A CNAME record." + }, + "nullable": true + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/CNAME@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonecname.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CNAME record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CNAME record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CNAME record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] }, - "cognitiveService_deployments": { + "privateDnsZone_MX": { "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 + "name": "privateDnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" + }, + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "2977624679479439942" + }, + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "mxRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/MX@2024-06-01#properties/properties/properties/mxRecords" + }, + "description": "Optional. The list of MX records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonemx.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" - }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - } + "dependsOn": [ + "privateDnsZone" + ] }, - "cognitiveService_diagnosticSettings": { + "privateDnsZone_PTR": { "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "name": "privateDnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + }, + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15286275176817336979" + }, + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PTR record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ptrRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/PTR@2024-06-01#properties/properties/properties/ptrRecords" + }, + "description": "Optional. The list of PTR records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszoneptr.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - } - }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + } }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } + "dependsOn": [ + "privateDnsZone" + ] }, - "cognitiveService_privateEndpoints": { + "privateDnsZone_SOA": { "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "name": "privateDnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + "privateDnsZoneName": { + "value": "[parameters('name')]" }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "name": { + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -38826,98 +23339,594 @@ "_generator": { "name": "bicep", "version": "0.41.2.15936", - "templateHash": "18436885663402767850" + "templateHash": "4837447718856535826" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." }, "definitions": { - "privateDnsZoneGroupType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, + "roleDefinitionIdOrName": { + "type": "string", "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { + }, + "principalId": { "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The principal type of the assigned principal ID." } }, - "kind": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { "type": "string", "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" + "2.0" ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. Version of the condition." } }, - "notes": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the notes of the lock." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "description": "An AVM-aligned type for a lock.", + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } }, - "privateDnsZoneGroupConfigType": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "soaRecord": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SOA@2024-06-01#properties/properties/properties/soaRecord" + }, + "description": "Optional. A SOA record." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesoa.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SRV": { + "copy": { + "name": "privateDnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15028912535488490265" + }, + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "privateDnsZoneResourceId": { + "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "srvRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/SRV@2024-06-01#properties/properties/properties/srvRecords" + }, + "description": "Optional. The list of SRV records in the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonesrv.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_TXT": { + "copy": { + "name": "privateDnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" + }, + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "7641583415110009849" }, + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." + }, + "definitions": { "roleAssignmentType": { "type": "object", "properties": { @@ -38989,80 +23998,56 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } }, "parameters": { - "name": { + "privateDnsZoneName": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." } }, - "subnetResourceId": { + "name": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Required. The name of the TXT record." } }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, + "metadata": { + "type": "object", "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, + "ttl": { + "type": "int", + "defaultValue": 3600, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. The TTL (time-to-live) of the records in the record set." } }, - "ipConfigurations": { + "txtRecords": { "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. The list of TXT records in the record set." }, "nullable": true }, - "ipVersionType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Enable/Disable usage telemetry for module." } }, "roleAssignments": { @@ -39074,53 +24059,6 @@ "metadata": { "description": "Optional. Array of role assignments to create." } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } } }, "variables": { @@ -39133,23 +24071,20 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -39165,56 +24100,31 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" } }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { + "TXT_roleAssignments": { "copy": { - "name": "privateEndpoint_roleAssignments", + "name": "TXT_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -39225,230 +24135,76 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" + "TXT" ] } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The name of the deployed TXT record." }, "value": "[parameters('name')]" }, - "location": { + "resourceId": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The resource ID of the deployed TXT record." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" }, - "groupId": { + "resourceGroupName": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The resource group of the deployed TXT record." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[resourceGroup().name]" } } } - } + }, + "dependsOn": [ + "privateDnsZone" + ] }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + "privateDnsZoneName": { + "value": "[parameters('name')]" }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" } }, "template": { @@ -39458,128 +24214,772 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13560950051680758953" - } + "version": "0.41.2.15936", + "templateHash": "7392770862892927923" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." }, - "definitions": { - "secretSetOutputType": { + "parameters": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonevnetlink.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } } }, - "secretToSetType": { - "type": "object", + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "resolutionPolicy": "[parameters('resolutionPolicy')]" } } }, - "parameters": { - "keyVaultName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." - } + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the private DNS zone." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.network.private-dns-zone.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the private DNS zone." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.network.private-dns-zone.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.private-endpoint.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": { + "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", + "properties": { + "privateLinkServiceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]", + "groupIds": [ + "account" + ] + } + } + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "name": "ai-services-dns-zone-cognitiveservices", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cognitiveServices), 64)), '2025-04-01').outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-openai", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').openAI), 64)), '2025-04-01').outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-aiservices", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').aiServices), 64)), '2025-04-01').outputs.resourceId.value]" + }, + { + "name": "ai-services-dns-zone-contentunderstanding", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').contentUnderstanding), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] + } + }, + "subnetResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2838568424679140846" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the private endpoint." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the custom network interface." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "description": "Private link service connections." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Private DNS zone group configuration." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the subnet used by the private endpoint." + } + } + }, + "resources": { + "privateEndpoint": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-endpoint.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "customNetworkInterfaceName": "[if(not(empty(parameters('customNetworkInterfaceName'))), createObject('value', parameters('customNetworkInterfaceName')), createObject('value', null()))]", + "privateLinkServiceConnections": { + "value": "[parameters('privateLinkServiceConnections')]" + }, + "privateDnsZoneGroup": { + "value": "[parameters('privateDnsZoneGroup')]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } } } }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -39587,22 +24987,13 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" }, - "aiServicesName": { + "privateEndpointName": { "value": "[parameters('name')]" }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" } }, "template": { @@ -39612,171 +25003,285 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" - } + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." }, "definitions": { - "aiProjectOutputType": { + "privateDnsZoneGroupConfigType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." + "description": "Optional. The name of the private DNS zone group config." } }, - "apiEndpoint": { + "privateDnsZoneResourceId": { "type": "string", "metadata": { - "description": "Required. API endpoint for the AI project." + "description": "Required. The resource id of the private DNS zone." } } }, "metadata": { "__bicep_export!": true, - "description": "Output type representing AI project information." + "description": "The type of a private DNS zone group configuration." } } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services project." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. The location of the Project resource." - } - }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } - }, - "aiServicesName": { + "privateEndpointName": { "type": "string", "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "tags": { - "type": "object", - "defaultValue": {}, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, "metadata": { - "description": "Optional. Tags to be applied to the resources." + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." } }, - "azureExistingAIProjectResourceId": { + "name": { "type": "string", - "defaultValue": "", + "defaultValue": "default", "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + "description": "Optional. The name of the private DNS zone group." } } }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, "resources": { - "cogServiceReference": { + "privateEndpoint": { "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] } } }, "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", + "name": { + "type": "string", "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." + "description": "The name of the private endpoint DNS zone group." }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" } } } - } + }, + "dependsOn": [ + "privateEndpoint" + ] } }, "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", + "resourceGroupName": { + "type": "string", "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + "description": "The resource group the private endpoint was deployed into." }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + "value": "[resourceGroup().name]" }, - "privateEndpoints": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "type": "string" }, "metadata": { - "description": "The private endpoints of the congitive services account." + "description": "The resource IDs of the network interfaces associated with the private endpoint." }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the private endpoint." }, - "dependsOn": [ - "cognitiveServiceNew" - ] + "value": "[reference('privateEndpoint').outputs.resourceId.value]" }, - "existing_cognitive_service_dependencies": { - "condition": "[variables('useExistingService')]", + "name": { + "type": "string", + "metadata": { + "description": "Name of the private endpoint." + }, + "value": "[reference('privateEndpoint').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').aiServices), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cognitiveServices), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').contentUnderstanding), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').openAI), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -39784,43 +25289,16 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('existingFoundryProjectResourceId')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "deployments": { - "value": "[parameters('deployments')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" - }, - "sku": { - "value": "[parameters('sku')]" + "value": "[parameters('identityName')]" + }, + "location": { + "value": "[parameters('location')]" }, "tags": { "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -39830,694 +25308,693 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8883353547455396972" - } + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." }, "definitions": { - "privateEndpointOutputType": { + "federatedIdentityCredentialType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "Required. The name of the federated identity credential." } }, - "resourceId": { - "type": "string", + "audiences": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "The resource ID of the private endpoint." + "description": "Required. The list of audiences that can appear in the issued token." } }, - "groupId": { + "issuer": { "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, "metadata": { - "description": "The custom DNS configurations of the private endpoint." + "description": "Required. The URL of the issuer to be trusted." } }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "subject": { + "type": "string", "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." + "description": "Required. The identifier of the external identity." } } }, "metadata": { "__bicep_export!": true, - "description": "The type for the private endpoint output." + "description": "The type for the federated identity credential." } }, - "deploymentType": { + "lockType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." + "description": "Optional. Specify the name of lock." } }, - "raiPolicyName": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { - "description": "Optional. The name of RAI policy." + "description": "Optional. Specify the type of lock." } }, - "versionUpgradeOption": { + "notes": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The version upgrade option." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } } }, - "endpointType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Type of the endpoint." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "endpoint": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, "metadata": { - "description": "The endpoint URI." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { + }, + "principalId": { "type": "string", "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "accessKey1Name": { + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." + "description": "Optional. The principal type of the assigned principal ID." } }, - "accessKey2Name": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." + "description": "Optional. The description of the role assignment." } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { + }, + "condition": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { + "conditionVersion": { "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Optional. Version of the condition." } }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { + "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/federatedIdentityCredentialType" }, + "nullable": true, "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." } }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Optional. Array of role assignments to create." } }, - "aiProjectOutputType": { + "tags": { "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } + "description": "Optional. Tags of the resource." }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "diagnosticSettingFullType": { - "type": "object", + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } } } }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" }, - "privateEndpointSingleServiceType": { + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "identityName": { + "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5270291310649425810" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for resource naming." + } + }, + "identityName": { + "type": "string", + "defaultValue": "[format('id-{0}', parameters('solutionName'))]", + "metadata": { + "description": "Name of the managed identity." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('identityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "7591858083424858339" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "federatedIdentityCredentialType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + "description": "Required. The name of the federated identity credential." } }, - "applicationSecurityGroupResourceIds": { + "audiences": { "type": "array", "items": { "type": "string" }, - "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + "description": "Required. The list of audiences that can appear in the issued token." } }, - "customNetworkInterfaceName": { + "issuer": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + "description": "Required. The URL of the issuer to be trusted." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "subject": { + "type": "string", "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Required. The identifier of the external identity." } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the federated identity credential." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Specify the name of lock." } }, - "tags": { - "type": "object", + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + "description": "Optional. Specify the type of lock." } }, - "enableTelemetry": { - "type": "bool", + "notes": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Specify the notes of the lock." } } }, "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" } } }, @@ -40592,23 +26069,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } } @@ -40617,74 +26078,24 @@ "name": { "type": "string", "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "sku": { - "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Required. Name of the User Assigned Identity." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." + "description": "Optional. Location for all resources." } }, - "privateEndpoints": { + "federatedIdentityCredentials": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" + "$ref": "#/definitions/federatedIdentityCredentialType" }, "nullable": true, "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." } }, "lock": { @@ -40704,33 +26115,32 @@ "description": "Optional. Array of role assignments to create." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "projectName": { - "type": "string", + "tags": { + "type": "object", "metadata": { - "description": "Optional: Name for the project which needs to be created." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true }, - "projectDescription": { - "type": "string", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional: Description for the project which needs to be created." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "azureExistingAIProjectResourceId": { + "isolationScope": { "type": "string", - "defaultValue": "", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." } } }, @@ -40743,1912 +26153,4333 @@ } ], "builtInRoleNames": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false + } }, "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('name')]" - }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" - }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" - }, - "cognitiveService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - } - }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - } - }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } - }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1387931959101373036" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." }, "parameters": { - "name": { + "userAssignedIdentityName": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." } }, - "subnetResourceId": { + "name": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Required. The name of the secret." } }, - "applicationSecurityGroupResourceIds": { + "audiences": { "type": "array", - "items": { - "type": "string" - }, - "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." } }, - "customNetworkInterfaceName": { + "issuer": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." } }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { + "subject": { "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2024-11-30", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + } + ], + "outputs": { + "name": { + "type": "string", "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "description": "The name of the federated identity credential." }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } + "value": "[parameters('name')]" }, - "tags": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "The resource ID of the federated identity credential." }, - "nullable": true + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" }, - "customDnsConfigs": { - "type": "array", + "resourceGroupName": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." + "description": "The name of the resource group the federated identity credential was created in." }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "Client ID of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.clientId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the managed identity." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.managed-identity.user-assigned-identity.{0}', parameters('identityName')), 64)), '2025-04-01').outputs.name.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cr{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "acrPullPrincipalIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').containerRegistry), 64)), '2025-04-01').outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8138805991948000285" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name used for naming convention." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", + "metadata": { + "description": "Name of the container registry." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for deployment." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Resource tags." + } + }, + "sku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "SKU for the container registry." + } + }, + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable admin user for the registry." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Public network access setting." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "metadata": { + "description": "Export policy status. Must be \"enabled\" when publicNetworkAccess is \"Enabled\"." + } + }, + "acrPullPrincipalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Principal IDs to assign AcrPull role." + } + }, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable private networking." + } + }, + "privateEndpointSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for private endpoint." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Private DNS zone resource IDs for private endpoint." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Azure telemetry collection." + } + } + }, + "variables": { + "copy": [ + { + "name": "roleAssignments", + "count": "[length(parameters('acrPullPrincipalIds'))]", + "input": { + "principalId": "[parameters('acrPullPrincipalIds')[copyIndex('roleAssignments')]]", + "roleDefinitionIdOrName": "[variables('acrPullRoleId')]", + "principalType": "ServicePrincipal" + } + }, + { + "name": "dnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('config{0}', copyIndex('dnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('dnsZoneConfigs')]]" + } + } + ], + "acrPullRoleId": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "privateEndpointConfig": "[if(and(parameters('enablePrivateNetworking'), not(empty(parameters('privateEndpointSubnetId')))), createArray(createObject('subnetResourceId', parameters('privateEndpointSubnetId'), 'privateDnsZoneGroup', if(not(empty(parameters('privateDnsZoneResourceIds'))), createObject('privateDnsZoneGroupConfigs', variables('dnsZoneConfigs')), null()))), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.containerregistry.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "acrSku": { + "value": "[parameters('sku')]" + }, + "acrAdminUserEnabled": { + "value": "[parameters('adminUserEnabled')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "exportPolicyStatus": { + "value": "[parameters('exportPolicyStatus')]" + }, + "roleAssignments": "[if(not(empty(parameters('acrPullPrincipalIds'))), createObject('value', variables('roleAssignments')), createObject('value', createArray()))]", + "privateEndpoints": { + "value": "[variables('privateEndpointConfig')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1509121545318808417" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR)." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + "ipAddresses": { + "type": "array", + "items": { + "type": "string" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "credentialSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a credential set." + } + }, + "scopeMapsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/scopeMaps@2025-03-01-preview#properties/properties/properties/actions" }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a scope map." + } + }, + "cacheRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cache rule." + } + }, + "replicationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-03-01-preview#properties/tags" }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-03-01-preview#properties/properties/properties/zoneRedundancy" }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replication." + } + }, + "taskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } + "description": "Optional. Tags of the resource." }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "description": "Optional. The platform properties for the task." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" + "description": "Optional. The step properties for the task." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + "description": "Optional. The trigger properties for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/status" }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "description": "Optional. The status of the task at the time the operation was called." + }, + "nullable": true + }, + "timeout": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The timeout in seconds for the task to run before it is automatically disabled." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "description": "Optional. The agent configuration for the task." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the agent pool to run the task on. If not specified, the task will run on Microsoft-hosted agents." + } + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether this is a system task or not. System tasks have some additional restrictions and are used for internal purposes by Microsoft services, such as Azure DevOps pipelines integration." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The log template for the task to use when creating logs in Log Analytics." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a task." + } + }, + "tokenType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map which defines the permissions for this token." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/status" }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } + "description": "Optional. The status of the token at the time the operation was called." + }, + "nullable": true + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of credentials associated with the token. Usually consists of a primary and an optional secondary credential." } } } }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "webhookType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/status" + }, + "description": "Optional. The status of the webhook at the time the operation was called." }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + "nullable": true + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "location": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13560950051680758953" - } + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-03-01-preview#properties/properties/properties/customHeaders" + }, + "description": "Optional. Custom headers that will be added to the webhook notifications." + }, + "nullable": true + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a webhook." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, + "memberName": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." } - } - }, - "parameters": { - "keyVaultName": { + }, + "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. The name of the Key Vault to set the secrets in." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } } } }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2026-02-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "description": "The type for auth credentials.", + "__bicep_imported_from!": { + "sourceTemplate": "credential-set/main.bicep" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2026-02-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", + "lockType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "location": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" - } + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } - } + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services project." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. The location of the Project resource." - } - }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } - }, - "aiServicesName": { - "type": "string", - "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" - } - } + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-12-01", - "name": "[parameters('aiServicesName')]" + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" - } - } - }, - "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." - }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } - } + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } } }, - "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + "description": "Required. Name of your Azure Container Registry." + } }, - "privateEndpoints": { + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "$ref": "#/definitions/roleAssignmentType" }, + "nullable": true, "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } + "description": "Optional. Array of role assignments to create." } }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The service endpoint of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" - }, - "endpoints": { - "$ref": "#/definitions/endpointType", - "metadata": { - "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" - } - } - } - }, - "dependsOn": [ - "avmContainerApp", - "avmContainerApp_Workflow", - "avmManagedIdentity", - "logAnalyticsWorkspace" - ] - }, - "cognitiveServicePrivateEndpoint": { - "condition": "[and(parameters('enablePrivateNetworking'), empty(variables('existingProjectResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.network.private-endpoint.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('pep-aiservices-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "customNetworkInterfaceName": { - "value": "[format('nic-aiservices-{0}', variables('solutionSuffix'))]" - }, - "privateLinkServiceConnections": { - "value": [ - { - "name": "[format('pep-aiservices-{0}-cognitiveservices-connection', variables('solutionSuffix'))]", - "properties": { - "privateLinkServiceId": "[reference('avmAiServices').outputs.resourceId.value]", - "groupIds": [ - "account" - ] - } - } - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDnsZoneGroupConfigs": [ - { - "name": "ai-services-dns-zone-cognitiveservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-openai", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-aiservices", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]" - }, - { - "name": "ai-services-dns-zone-contentunderstanding", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]" - } - ] - } - }, - "subnetResourceId": { - "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "18436885663402767850" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "ipVersionType": { - "type": "string", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" - }, - "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." - }, - "defaultValue": "IPv4" - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "autoGeneratedDomainNameLabelScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse", + "Unsecure" + ], + "metadata": { + "description": "Optional. The domain name label reuse scope." + } + }, + "roleAssignmentMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AbacRepositoryPermissions", + "LegacyRegistryPermissions" + ], + "metadata": { + "description": "Optional. The registry permissions role assignment mode." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registry is enabled or not. Default is disabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'. Set to an empty array to explicitly configure no allowed IPs." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "items": { + "$ref": "#/definitions/replicationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/webhookType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries@2025-04-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service. If neither metrics nor logs are specified, all metrics & logs are configured by default. If either one is specified, the other is ignored." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "items": { + "$ref": "#/definitions/cacheRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialSetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/scopeMapsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Scope maps setting." + } + }, + "tokens": { + "type": "array", + "items": { + "$ref": "#/definitions/tokenType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tokens to create for the container registry." + } + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/definitions/taskType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of ACR Tasks to create." + } } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - }, - "ipVersionType": "[parameters('ipVersionType')]" - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" }, - "privateEndpointName": { - "value": "[parameters('name')]" + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Container Registry Repository Catalog Lister": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'bfdb9389-c9a5-478a-bb2f-ba9ca092c3c7')]", + "Container Registry Repository Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2efddaa5-3f1f-4df3-97df-af3f13818f4c')]", + "Container Registry Repository Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b93aa761-3e63-49ed-ac28-beffa264f7ac')]", + "Container Registry Repository Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a1e307c-b015-4ebd-883e-5b7698a07328')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "publicNetworkAccessMode": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "shouldConfigureNetworkRuleSet": "[or(not(equals(parameters('networkRuleSetIpRules'), null())), and(equals(variables('publicNetworkAccessMode'), 'Enabled'), equals(parameters('networkRuleSetDefaultAction'), 'Deny')))]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.41.2.15936", - "templateHash": "9935179114830442414" + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.12.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "autoGeneratedDomainNameLabelScope": "[parameters('autoGeneratedDomainNameLabelScope')]", + "roleAssignmentMode": "[parameters('roleAssignmentMode')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[variables('publicNetworkAccessMode')]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(variables('shouldConfigureNetworkRuleSet'), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', coalesce(parameters('networkRuleSetIpRules'), createArray())), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "registry_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray())))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups')), createArray(createObject('category', 'AllMetrics')), createArray()))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray())))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), if(empty(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories')), createArray(createObject('categoryGroup', 'allLogs')), createArray()))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3787322352564227867" + }, + "name": "Container Registries scope maps", + "description": "This module deploys an Azure Container Registry (ACR) scope map." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-scopemap.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "6219097750044645017" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/replications@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-repl.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13412699468141336519" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set." + }, + "definitions": { + "authCredentialsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for auth credentials." + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only system-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlySysAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authCredentials": { + "type": "array", + "items": { + "$ref": "#/definitions/authCredentialsType" + }, + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-credset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('credentialSet', '2025-11-01', 'full'), 'identity'), 'principalId')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name')]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "1319901650921923538" + }, + "name": "Container Registry Cache", + "description": "The cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache))." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-'), '*', '')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the credential store which is associated with the cache rule. Required only when pulling from authenticated upstream registries (e.g., Docker Hub). Omit for anonymous public registries such as MCR (mcr.microsoft.com)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-cacherule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "cacheRule": { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_tokens": { + "copy": { + "name": "registry_tokens", + "count": "[length(coalesce(parameters('tokens'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Token-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "scopeMapResourceId": { + "value": "[coalesce(parameters('tokens'), createArray())[copyIndex()].scopeMapResourceId]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'status')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tokens'), createArray())[copyIndex()], 'credentials')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "5970335582661416899" + }, + "name": "Container Registries Tokens", + "description": "Deploys an Azure Container Registry (ACR) Token." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the token." + } + }, + "scopeMapResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scope map to which the token will be associated with." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the token. Default is enabled." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tokens@2025-11-01#properties/properties/properties/credentials" + }, + "description": "Optional. The credentials associated with the token for authentication." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-token.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "token": { + "type": "Microsoft.ContainerRegistry/registries/tokens", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "scopeMapId": "[parameters('scopeMapResourceId')]", + "status": "[parameters('status')]", + "credentials": "[if(not(empty(coalesce(parameters('credentials'), createArray()))), createObject('certificates', tryGet(parameters('credentials'), 'certificates'), 'passwords', tryGet(parameters('credentials'), 'passwords')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the token." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the token was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the token." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tokens', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_scopeMaps" + ] + }, + "registry_tasks": { + "copy": { + "name": "registry_tasks", + "count": "[length(coalesce(parameters('tasks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Task-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tasks'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "platform": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'platform')]" + }, + "step": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'step')]" + }, + "trigger": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'trigger')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'status')]" + }, + "timeout": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'timeout')]" + }, + "agentConfiguration": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentConfiguration')]" + }, + "agentPoolName": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'agentPoolName')]" + }, + "credentials": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'credentials')]" + }, + "isSystemTask": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'isSystemTask')]" + }, + "logTemplate": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'logTemplate')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('tasks'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "2468771835002458415" + }, + "name": "Container Registries Tasks", + "description": "Deploys an Azure Container Registry (ACR) Task that can be used to automate container image builds and other workflows ([ref](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview))." + }, + "definitions": { + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. The name of the task." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/platform" + }, + "description": "Optional. The platform properties against which the task has to run." + }, + "nullable": true + }, + "step": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/step" + }, + "description": "Optional. The task step properties. Exactly one of dockerBuildStep, encodedTaskStep, or fileTaskStep must be provided." + }, + "nullable": true + }, + "trigger": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/trigger" + }, + "description": "Optional. The properties that describe all triggers for the task." + }, + "nullable": true + }, + "status": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. The current status of task." + } + }, + "timeout": { + "type": "int", + "defaultValue": 3600, + "minValue": 300, + "maxValue": 28800, + "metadata": { + "description": "Optional. Run timeout in seconds." + } + }, + "agentConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/agentConfiguration" + }, + "description": "Optional. The machine configuration of the run agent." + }, + "nullable": true + }, + "agentPoolName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The dedicated agent pool for the task." + } + }, + "credentials": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/tasks@2025-03-01-preview#properties/properties/properties/credentials" + }, + "description": "Optional. The properties that describe the credentials that will be used when the task is invoked." + }, + "nullable": true + }, + "isSystemTask": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The value of this property indicates whether the task resource is system task or not." + } + }, + "logTemplate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The template that describes the repository and tag information for run log artifact." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-task.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "task": { + "type": "Microsoft.ContainerRegistry/registries/tasks", + "apiVersion": "2025-03-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "agentConfiguration": "[parameters('agentConfiguration')]", + "agentPoolName": "[parameters('agentPoolName')]", + "credentials": "[parameters('credentials')]", + "isSystemTask": "[parameters('isSystemTask')]", + "logTemplate": "[parameters('logTemplate')]", + "platform": "[parameters('platform')]", + "status": "[parameters('status')]", + "step": "[parameters('step')]", + "timeout": "[parameters('timeout')]", + "trigger": "[parameters('trigger')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the task." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the task was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the task." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/tasks', parameters('registryName'), parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('task', '2025-03-01-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('task', '2025-03-01-preview', 'full'), 'identity'), 'principalId')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "nullable": true, + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action')]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "3200175097987099858" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook." + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "securestring", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.ContainerRegistry/registries/webhooks@2025-11-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.containerregistry-registry-webhook.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-11-01", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2025-11-01", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2025-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, - "privateDnsZoneResourceId": { - "type": "string", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. The resource id of the private DNS zone." + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { + "type": "string", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } + "dependsOn": [ + "registry", + "registry_replications" + ] } }, - "parameters": { - "privateEndpointName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "description": "The Name of the Azure container registry." }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } + "value": "[parameters('name')]" }, - "name": { + "loginServer": { "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2025-05-01", - "name": "[parameters('privateEndpointName')]" + "description": "The reference to the Azure container registry." + }, + "value": "[reference('registry').loginServer]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The name of the Azure container registry." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the Azure container registry." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" }, - "resourceGroupName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The principal ID of the system assigned identity." }, - "value": "[resourceGroup().name]" + "value": "[tryGet(tryGet(reference('registry', '2025-06-01-preview', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2025-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[tryGet(tryGet(reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('credentialSets'), createArray()))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(coalesce(parameters('credentialSets'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Azure container registry." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } - }, - "dependsOn": [ - "privateEndpoint" - ] + } } - }, + ], "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "The name of the private endpoint." + "description": "The name of the container registry." }, - "value": "[parameters('name')]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.name.value]" }, - "location": { + "loginServer": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The login server URL." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.loginServer.value]" }, - "groupId": { + "resourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." + "description": "The resource ID of the container registry." }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.containerregistry.{0}', parameters('name')), 64)), '2025-04-01').outputs.resourceId.value]" } } } }, "dependsOn": [ - "avmAiServices", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", - "virtualNetwork" + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').containerRegistry), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmContainerAppEnv": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -42669,7 +30500,7 @@ "systemAssigned": true } }, - "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]", + "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value)), createObject('value', null()))]", "workloadProfiles": { "value": [ { @@ -42685,395 +30516,62 @@ "value": "Enabled" }, "platformReservedCidr": { - "value": "172.17.17.0/24" - }, - "platformReservedDnsIP": { - "value": "172.17.17.17" - }, - "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", - "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "11924518395502120940" - }, - "name": "App ManagedEnvironments", - "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." - }, - "definitions": { - "certificateType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the certificate." - } - }, - "certificateType": { - "type": "string", - "allowedValues": [ - "ImagePullTrustedCA", - "ServerSSLCertificate" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the certificate." - } - }, - "certificateValue": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." - } - }, - "certificatePassword": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The password of the certificate." - } - }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", - "nullable": true, - "metadata": { - "description": "Optional. A key vault reference." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location for the resource." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a certificate." - } - }, - "storageType": { - "type": "object", - "properties": { - "accessMode": { - "type": "string", - "allowedValues": [ - "ReadOnly", - "ReadWrite" - ], - "metadata": { - "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Required. Storage account name." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. File share name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the storage." - } - }, - "appLogsConfigurationType": { - "type": "object", - "discriminator": { - "propertyName": "destination", - "mapping": { - "azure-monitor": { - "$ref": "#/definitions/appLogsConfigurationMonitorType" - }, - "log-analytics": { - "$ref": "#/definitions/appLogsConfigurationLawType" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the App Logs Configuration." - } - }, - "appLogsConfigurationMonitorType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "azure-monitor" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using azure-monitor." - } - }, - "appLogsConfigurationLawType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "allowedValues": [ - "log-analytics" - ], - "metadata": { - "description": "Required. The destination of the logs." - } - }, - "logAnalyticsWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Existing Log Analytics Workspace resource ID." - } - } - }, - "metadata": { - "description": "The type for the App Logs Configuration if using log-analytics." - } - }, - "certificateKeyVaultPropertiesType": { - "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } - }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } - }, - "metadata": { - "description": "The type for the certificate's key vault properties.", - "__bicep_imported_from!": { - "sourceTemplate": "certificate/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } + "value": "172.17.17.0/24" + }, + "platformReservedDnsIP": { + "value": "172.17.17.17" + }, + "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]", + "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.webserverfarmSubnetResourceId.value), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8036802024102680577" } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the Container Apps Managed Environment." + "description": "Name of the container app environment." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Azure region for the resource." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", + "type": "object", + "metadata": { + "description": "Managed identity configuration." + } + }, + "appLogsConfiguration": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Optional. Application logs configuration." } }, - "roleAssignments": { + "workloadProfiles": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Workload profiles for the environment." } }, "enableTelemetry": { @@ -43083,345 +30581,47 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "appInsightsConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string." - } - }, - "daprConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" - }, - "description": "Optional. The configuration of Dapr component." - }, - "nullable": true - }, - "ingressConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" - }, - "description": "Optional. Ingress configuration for the Managed Environment." - }, - "nullable": true - }, - "kedaConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" - }, - "description": "Optional. The configuration of Keda component." - }, - "nullable": true - }, - "peerAuthentication": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" - }, - "description": "Optional. Peer authentication settings for the Managed Environment." - }, - "nullable": true - }, - "daprAIConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." - } - }, - "daprAIInstrumentationKey": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." - } - }, - "dockerBridgeCidr": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "infrastructureSubnetResourceId": { + "publicNetworkAccess": { "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "internal": { - "type": "bool", - "defaultValue": false, + "defaultValue": "Enabled", "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Public network access setting." } }, "platformReservedCidr": { "type": "string", "defaultValue": "", "metadata": { - "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Optional. Platform reserved CIDR block." } }, "platformReservedDnsIP": { "type": "string", "defaultValue": "", "metadata": { - "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "peerTrafficEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not to encrypt peer traffic." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether to allow or block all public traffic." + "description": "Optional. Platform reserved DNS IP." } }, "zoneRedundant": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not this Managed Environment is zone-redundant." - } - }, - "certificatePassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Password of the certificate used by the custom domain." - } - }, - "certificateValue": { - "type": "securestring", - "nullable": true, + "defaultValue": false, "metadata": { - "description": "Optional. Certificate to use for the custom domain. PFX or PEM." + "description": "Whether the environment is zone redundant." } }, - "dnsSuffix": { + "infrastructureSubnetResourceId": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. DNS suffix for the environment domain." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "openTelemetryConfiguration": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" - }, - "description": "Optional. Open Telemetry configuration." - }, - "nullable": true - }, - "workloadProfiles": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" - }, - "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." - }, - "nullable": true - }, - "infrastructureResourceGroupName": { - "type": "string", - "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", - "metadata": { - "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "storages": { - "type": "array", - "items": { - "$ref": "#/definitions/storageType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of storages to mount on the environment." - } - }, - "certificate": { - "$ref": "#/definitions/certificateType", - "nullable": true, - "metadata": { - "description": "Optional. A Managed Environment Certificate." - } - }, - "appLogsConfiguration": { - "$ref": "#/definitions/appLogsConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The AppLogsConfiguration for the Managed Environment." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "description": "Optional. Infrastructure subnet resource ID." } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-11-01", - "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", - "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" - }, - "managedEnvironment": { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "appInsightsConfiguration": { - "connectionString": "[parameters('appInsightsConnectionString')]" - }, - "daprConfiguration": "[parameters('daprConfiguration')]", - "ingressConfiguration": "[parameters('ingressConfiguration')]", - "kedaConfiguration": "[parameters('kedaConfiguration')]", - "peerAuthentication": "[parameters('peerAuthentication')]", - "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", - "daprAIConnectionString": "[parameters('daprAIConnectionString')]", - "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", - "customDomainConfiguration": { - "certificatePassword": "[parameters('certificatePassword')]", - "certificateValue": "[parameters('certificateValue')]", - "dnsSuffix": "[parameters('dnsSuffix')]", - "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" - }, - "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", - "peerTrafficConfiguration": { - "encryption": { - "enabled": "[parameters('peerTrafficEncryption')]" - } - }, - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "vnetConfiguration": { - "internal": "[parameters('internal')]", - "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", - "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", - "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", - "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" - }, - "workloadProfiles": "[parameters('workloadProfiles')]", - "zoneRedundant": "[parameters('zoneRedundant')]", - "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "managedEnvironment_roleAssignments": { - "copy": { - "name": "managedEnvironment_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_storage": { - "copy": { - "name": "managedEnvironment_storage", - "count": "[length(coalesce(parameters('storages'), createArray()))]" - }, + "containerAppEnvironment": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[take(format('avm.res.app.managed-environment.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -43429,20 +30629,35 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" - }, - "managedEnvironmentName": { "value": "[parameters('name')]" }, - "kind": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" }, - "accessMode": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + "managedIdentities": { + "value": "[parameters('managedIdentities')]" }, - "storageAccountName": { - "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" - } + "appLogsConfiguration": { + "value": "[parameters('appLogsConfiguration')]" + }, + "workloadProfiles": { + "value": "[parameters('workloadProfiles')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "platformReservedCidr": "[if(not(empty(parameters('platformReservedCidr'))), createObject('value', parameters('platformReservedCidr')), createObject('value', null()))]", + "platformReservedDnsIP": "[if(not(empty(parameters('platformReservedDnsIP'))), createObject('value', parameters('platformReservedDnsIP')), createObject('value', null()))]", + "zoneRedundant": { + "value": "[parameters('zoneRedundant')]" + }, + "infrastructureSubnetResourceId": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), createObject('value', parameters('infrastructureSubnetResourceId')), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -43452,162 +30667,337 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "945327737463253676" + "templateHash": "11924518395502120940" }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." + "name": "App ManagedEnvironments", + "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." }, - "parameters": { - "name": { - "type": "string", + "definitions": { + "certificateType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the certificate." + } + }, + "certificateType": { + "type": "string", + "allowedValues": [ + "ImagePullTrustedCA", + "ServerSSLCertificate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location for the resource." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, "metadata": { - "description": "Required. The name of the file share." + "__bicep_export!": true, + "description": "The type for a certificate." } }, - "managedEnvironmentName": { - "type": "string", + "storageType": { + "type": "object", + "properties": { + "accessMode": { + "type": "string", + "allowedValues": [ + "ReadOnly", + "ReadWrite" + ], + "metadata": { + "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. File share name." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type of the storage." } }, - "accessMode": { - "type": "string", + "appLogsConfigurationType": { + "type": "object", + "discriminator": { + "propertyName": "destination", + "mapping": { + "azure-monitor": { + "$ref": "#/definitions/appLogsConfigurationMonitorType" + }, + "log-analytics": { + "$ref": "#/definitions/appLogsConfigurationLawType" + } + } + }, "metadata": { - "description": "Required. The access mode for the storage." + "__bicep_export!": true, + "description": "The type for the App Logs Configuration." } }, - "kind": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], + "appLogsConfigurationMonitorType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "azure-monitor" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + } + }, "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + "description": "The type for the App Logs Configuration if using azure-monitor." } }, - "storageAccountName": { - "type": "string", + "appLogsConfigurationLawType": { + "type": "object", + "properties": { + "destination": { + "type": "string", + "allowedValues": [ + "log-analytics" + ], + "metadata": { + "description": "Required. The destination of the logs." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Existing Log Analytics Workspace resource ID." + } + } + }, "metadata": { - "description": "Required. Storage account name." + "description": "The type for the App Logs Configuration if using log-analytics." } - } - }, - "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" }, - "storage": { - "type": "Microsoft.App/managedEnvironments/storages", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "certificateKeyVaultPropertiesType": { + "type": "object", "properties": { - "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", - "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the file share." + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the file share." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" + "description": "The type for the certificate's key vault properties.", + "__bicep_imported_from!": { + "sourceTemplate": "certificate/main.bicep" + } + } }, - "resourceGroupName": { - "type": "string", + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, "metadata": { - "description": "The resource group the file share was deployed into." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_certificate": { - "condition": "[not(empty(parameters('certificate')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" - }, - "managedEnvironmentName": { - "value": "[parameters('name')]" - }, - "certificateKeyVaultProperties": { - "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" - }, - "certificateType": { - "value": "[tryGet(parameters('certificate'), 'certificateType')]" - }, - "certificateValue": { - "value": "[tryGet(parameters('certificate'), 'certificateValue')]" - }, - "certificatePassword": { - "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" - }, - "location": { - "value": "[tryGet(parameters('certificate'), 'location')]" - }, - "tags": { - "value": "[tryGet(parameters('certificate'), 'tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "574133184207535827" + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." - }, - "definitions": { - "certificateKeyVaultPropertiesType": { + "roleAssignmentType": { "type": "object", "properties": { - "identityResourceId": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + "description": "Optional. The principal type of the assigned principal ID." } }, - "keyVaultUrl": { + "description": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type for the certificate's key vault properties." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } } }, @@ -43615,13 +31005,7 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the Container Apps Managed Environment Certificate." - } - }, - "managedEnvironmentName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + "description": "Required. Name of the Container Apps Managed Environment." } }, "location": { @@ -43631,1750 +31015,879 @@ "description": "Optional. Location for all Resources." } }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", "nullable": true, "metadata": { - "description": "Optional. A key vault reference to the certificate to use for the custom domain." + "description": "Optional. The managed identity definition for this resource." } }, - "certificateType": { - "type": "string", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, - "allowedValues": [ - "ServerSSLCertificate", - "ImagePullTrustedCA" - ], "metadata": { - "description": "Optional. The type of the certificate." + "description": "Optional. Array of role assignments to create." } }, - "certificateValue": { - "type": "string", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "certificatePassword": { + "appInsightsConnectionString": { "type": "securestring", - "nullable": true, + "defaultValue": "", "metadata": { - "description": "Optional. The password of the certificate." + "description": "Optional. Application Insights connection string." } }, - "tags": { + "daprConfiguration": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/daprConfiguration" }, - "description": "Optional. Tags of the resource." + "description": "Optional. The configuration of Dapr component." }, "nullable": true - } - }, - "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2025-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" }, - "managedEnvironmentCertificate": { - "type": "Microsoft.App/managedEnvironments/certificates", - "apiVersion": "2025-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", - "certificateType": "[parameters('certificateType')]", - "password": "[parameters('certificatePassword')]", - "value": "[parameters('certificateValue')]" + "ingressConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/ingressConfiguration" + }, + "description": "Optional. Ingress configuration for the Managed Environment." }, - "tags": "[parameters('tags')]" - } - }, - "outputs": { - "name": { - "type": "string", + "nullable": true + }, + "kedaConfiguration": { + "type": "object", "metadata": { - "description": "The name of the key values." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/kedaConfiguration" + }, + "description": "Optional. The configuration of Keda component." }, - "value": "[parameters('name')]" + "nullable": true }, - "resourceId": { - "type": "string", + "peerAuthentication": { + "type": "object", "metadata": { - "description": "The resource ID of the key values." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/peerAuthentication" + }, + "description": "Optional. Peer authentication settings for the Managed Environment." }, - "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + "nullable": true }, - "resourceGroupName": { + "daprAIConnectionString": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." + } + }, + "daprAIInstrumentationKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." + } + }, + "dockerBridgeCidr": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The resource group the certificate was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Managed Environment was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Managed Environment." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Managed Environment." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" - }, - "defaultDomain": { - "type": "string", - "metadata": { - "description": "The Default domain of the Managed Environment." - }, - "value": "[reference('managedEnvironment').defaultDomain]" - }, - "staticIp": { - "type": "string", - "metadata": { - "description": "The IP address of the Managed Environment." - }, - "value": "[reference('managedEnvironment').staticIp]" - }, - "domainVerificationId": { - "type": "string", - "metadata": { - "description": "The domain verification id for custom domains." - }, - "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "avmContainerRegistryReader": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('id-acr-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "7591858083424858339" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." - }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "isolationScope": { - "type": "string", - "nullable": true, - "allowedValues": [ - "None", - "Regional" - ], - "metadata": { - "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" - }, - "userAssignedIdentity_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(subscription().id, resourceGroup().id, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" - }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" - }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" - }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "1387931959101373036" + "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "infrastructureSubnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "internal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetResourceId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedCidr": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "platformReservedDnsIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." + } }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." - }, - "parameters": { - "userAssignedIdentityName": { - "type": "string", + "peerTrafficEncryption": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + "description": "Optional. Whether or not to encrypt peer traffic." } }, - "name": { + "publicNetworkAccess": { "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Required. The name of the secret." + "description": "Optional. Whether to allow or block all public traffic." } }, - "audiences": { - "type": "array", + "zoneRedundant": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + "description": "Optional. Whether or not this Managed Environment is zone-redundant." } }, - "issuer": { - "type": "string", + "certificatePassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Password of the certificate used by the custom domain." + } + }, + "certificateValue": { + "type": "securestring", + "nullable": true, "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + "description": "Optional. Certificate to use for the custom domain. PFX or PEM." } }, - "subject": { + "dnsSuffix": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + "description": "Optional. DNS suffix for the environment domain." } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } - } - ], - "outputs": { - "name": { - "type": "string", + }, + "openTelemetryConfiguration": { + "type": "object", "metadata": { - "description": "The name of the federated identity credential." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-02-02-preview#properties/properties/properties/openTelemetryConfiguration" + }, + "description": "Optional. Open Telemetry configuration." }, - "value": "[parameters('name')]" + "nullable": true }, - "resourceId": { - "type": "string", + "workloadProfiles": { + "type": "array", "metadata": { - "description": "The resource ID of the federated identity credential." + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments@2025-10-02-preview#properties/properties/properties/workloadProfiles" + }, + "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "nullable": true }, - "resourceGroupName": { + "infrastructureResourceGroupName": { "type": "string", + "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", "metadata": { - "description": "The name of the resource group the federated identity credential was created in." + "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." + } + }, + "storages": { + "type": "array", + "items": { + "$ref": "#/definitions/storageType" }, - "value": "[resourceGroup().name]" + "nullable": true, + "metadata": { + "description": "Optional. The list of storages to mount on the environment." + } + }, + "certificate": { + "$ref": "#/definitions/certificateType", + "nullable": true, + "metadata": { + "description": "Optional. A Managed Environment Certificate." + } + }, + "appLogsConfiguration": { + "$ref": "#/definitions/appLogsConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. The AppLogsConfiguration for the Managed Environment." + } } - } - } - }, - "dependsOn": [ - "userAssignedIdentity" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - }, - "avmContainerApp": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "registries": { - "value": null - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-11-01", + "name": "[format('46d3xbcp.res.app-managedenvironment.{0}.{1}', replace('0.13.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "logAnalyticsWorkspace": { + "condition": "[not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2025-02-01", + "subscriptionId": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'), '/'))]" }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "managedEnvironment": { + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "appInsightsConfiguration": { + "connectionString": "[parameters('appInsightsConnectionString')]" + }, + "daprConfiguration": "[parameters('daprConfiguration')]", + "ingressConfiguration": "[parameters('ingressConfiguration')]", + "kedaConfiguration": "[parameters('kedaConfiguration')]", + "peerAuthentication": "[parameters('peerAuthentication')]", + "appLogsConfiguration": "[if(not(empty(parameters('appLogsConfiguration'))), shallowMerge(createArray(createObject('destination', parameters('appLogsConfiguration').destination), if(not(empty(tryGet(parameters('appLogsConfiguration'), 'logAnalyticsWorkspaceResourceId'))), createObject('logAnalyticsConfiguration', createObject('customerId', reference('logAnalyticsWorkspace').customerId, 'sharedKey', listKeys('logAnalyticsWorkspace', '2025-02-01').primarySharedKey)), createObject()))), null())]", + "daprAIConnectionString": "[parameters('daprAIConnectionString')]", + "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", + "customDomainConfiguration": { + "certificatePassword": "[parameters('certificatePassword')]", + "certificateValue": "[parameters('certificateValue')]", + "dnsSuffix": "[parameters('dnsSuffix')]", + "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" + }, + "openTelemetryConfiguration": "[parameters('openTelemetryConfiguration')]", + "peerTrafficConfiguration": { + "encryption": { + "enabled": "[parameters('peerTrafficEncryption')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "vnetConfiguration": { + "internal": "[parameters('internal')]", + "infrastructureSubnetId": "[parameters('infrastructureSubnetResourceId')]", + "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", + "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", + "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" + }, + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]", + "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "managedEnvironment_roleAssignments": { + "copy": { + "name": "managedEnvironment_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedEnvironment" + ] }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "managedEnvironment_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "managedEnvironment" + ] }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "managedEnvironment_storage": { + "copy": { + "name": "managedEnvironment_storage", + "count": "[length(coalesce(parameters('storages'), createArray()))]" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Storage-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].name]" + }, + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "kind": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].kind]" + }, + "accessMode": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].accessMode]" + }, + "storageAccountName": { + "value": "[coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "945327737463253676" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "managedEnvironmentName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "accessMode": { + "type": "string", + "metadata": { + "description": "Required. The access mode for the storage." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Required. Type of storage: \"SMB\" or \"NFS\"." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Storage account name." + } + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "storage": { + "type": "Microsoft.App/managedEnvironments/storages", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "properties": { + "nfsAzureFile": "[if(equals(parameters('kind'), 'NFS'), createObject('accessMode', parameters('accessMode'), 'server', format('{0}.file.{1}', parameters('storageAccountName'), environment().suffixes.storage), 'shareName', format('/{0}/{1}', parameters('storageAccountName'), parameters('name'))), null())]", + "azureFile": "[if(equals(parameters('kind'), 'SMB'), createObject('accessMode', parameters('accessMode'), 'accountName', parameters('storageAccountName'), 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2025-01-01').keys[0].value, 'shareName', parameters('name')), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the file share." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments/storages', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the file share was deployed into." + }, + "value": "[resourceGroup().name]" + } + } } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + }, + "dependsOn": [ + "managedEnvironment" + ] + }, + "managedEnvironment_certificate": { + "condition": "[not(empty(parameters('certificate')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" + }, + "managedEnvironmentName": { + "value": "[parameters('name')]" + }, + "certificateKeyVaultProperties": { + "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" + }, + "certificateType": { + "value": "[tryGet(parameters('certificate'), 'certificateType')]" + }, + "certificateValue": { + "value": "[tryGet(parameters('certificate'), 'certificateValue')]" + }, + "certificatePassword": { + "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" + }, + "location": { + "value": "[tryGet(parameters('certificate'), 'location')]" + }, + "tags": { + "value": "[tryGet(parameters('certificate'), 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "574133184207535827" + }, + "name": "App ManagedEnvironments Certificates", + "description": "This module deploys a App Managed Environment Certificate." + }, + "definitions": { + "certificateKeyVaultPropertiesType": { + "type": "object", + "properties": { + "identityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." + } + }, + "keyVaultUrl": { + "type": "string", + "metadata": { + "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the certificate's key vault properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container Apps Managed Environment Certificate." + } + }, + "managedEnvironmentName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "certificateKeyVaultProperties": { + "$ref": "#/definitions/certificateKeyVaultPropertiesType", + "nullable": true, + "metadata": { + "description": "Optional. A key vault reference to the certificate to use for the custom domain." + } + }, + "certificateType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ServerSSLCertificate", + "ImagePullTrustedCA" + ], + "metadata": { + "description": "Optional. The type of the certificate." + } + }, + "certificateValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the certificate. PFX or PEM blob." + } + }, + "certificatePassword": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password of the certificate." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "resources": { + "managedEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2025-10-02-preview", + "name": "[parameters('managedEnvironmentName')]" + }, + "managedEnvironmentCertificate": { + "type": "Microsoft.App/managedEnvironments/certificates", + "apiVersion": "2025-10-02-preview", + "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", + "certificateType": "[parameters('certificateType')]", + "password": "[parameters('certificatePassword')]", + "value": "[parameters('certificateValue')]" + }, + "tags": "[parameters('tags')]" + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the certificate was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedEnvironment" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Managed Environment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedEnvironment', '2025-10-02-preview', 'full').location]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Managed Environment." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Managed Environment." + }, + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('managedEnvironment', '2025-10-02-preview', 'full'), 'identity'), 'principalId')]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('managedEnvironment').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The IP address of the Managed Environment." + }, + "value": "[reference('managedEnvironment').staticIp]" + }, + "domainVerificationId": { + "type": "string", + "metadata": { + "description": "The domain verification id for custom domains." + }, + "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } }, - "parameters": { - "name": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. Name of the Container App." - } + "description": "Resource ID of the container app environment." + }, + "value": "[reference('containerAppEnvironment').outputs.resourceId.value]" }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { + "description": "Name of the container app environment." + }, + "value": "[reference('containerAppEnvironment').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7070907820525585254" + } + }, + "parameters": { + "solutionSuffix": { "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + "description": "Unique solution suffix used to derive resource names." } }, - "clientCertificateMode": { + "location": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], "metadata": { - "description": "Optional. Client certificate mode for mTLS." + "description": "Azure region for the resource." } }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, + "environmentResourceId": { + "type": "string", "metadata": { - "description": "Optional. Object userd to configure CORS policy." + "description": "Resource ID of the container app environment." } }, - "stickySessionsAffinity": { + "containerRegistryEndpoint": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." + "description": "Container registry endpoint hosting the processor image." } }, - "ingressTransport": { + "imageTag": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], "metadata": { - "description": "Optional. Ingress transport protocol." + "description": "Image tag to deploy." } }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { + "enableScalability": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, "metadata": { - "description": "Optional. Settings to expose additional ports on container app." + "description": "Whether additional scale-out should be enabled." } }, - "ingressAllowInsecure": { + "enableMonitoring": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], + "defaultValue": false, "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + "description": "Whether monitoring is enabled." } }, - "environmentResourceId": { + "appInsightsConnectionString": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Application Insights connection string." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Tags to apply to the resource." } }, "enableTelemetry": { @@ -45384,334 +31897,114 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { + "userAssignedResourceIds": { "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { + "appConfigEndpoint": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "defaultValue": "", "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false + "containerAppName": "[format('ca-{0}-app', parameters('solutionSuffix'))]", + "containerName": "[format('ca-{0}', parameters('solutionSuffix'))]", + "scaleSettings": "[if(empty(parameters('appConfigEndpoint')), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1)), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1), 'rules', if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())))]" }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.container-app-processor.{0}', parameters('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "containers": { + "value": [ + { + "name": "[variables('containerName')]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "activeRevisionsMode": { + "value": "Single" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "ingressExternal": { + "value": false }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "disableIngress": { + "value": true }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "scaleSettings": { + "value": "[variables('scaleSettings')]" } }, "template": { @@ -45722,372 +32015,1846 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "11353975374580271835" + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Name of the container app." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "globalValidation": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } }, - "httpSettings": { + "managedIdentities": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } }, - "identityProviders": { + "scaleSettings": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } }, - "login": { - "type": "object", + "workloadProfileName": { + "type": "string", + "defaultValue": "", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Workload profile name." + } }, - "platform": { - "type": "object", + "disableIngress": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Whether ingress is disabled." + } }, - "enableTelemetry": { + "ingressAllowInsecure": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." } } }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "Name of the container app." }, - "value": "current" + "value": "[reference('containerApp').outputs.name.value]" }, - "resourceId": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Fully qualified domain name of the container app." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "resourceGroupName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[resourceGroup().name]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } - }, - "dependsOn": [ - "containerApp" - ] + } } }, "outputs": { "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." + "description": "Resource ID of the container app." }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the Container App was deployed into." + "description": "Name of the container app." }, - "value": "[resourceGroup().name]" + "value": "[reference('containerApp').outputs.name.value]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "The name of the Container App." + "description": "Fully qualified domain name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } }, "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmContainerApp_API": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" }, "location": { "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "workloadProfileName": { - "value": "Consumption" + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" }, - "registries": { - "value": null + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", "tags": { "value": "[parameters('tags')]" }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "containers": { + "userAssignedResourceIds": { "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 - } - ] - } + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" - } - } - } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } } }, "template": { @@ -46098,981 +33865,2156 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." + "templateHash": "17990158768842819361" + } }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, + "parameters": { + "solutionSuffix": { + "type": "string", "metadata": { - "description": "The type for a service binding." + "description": "Unique solution suffix used to derive resource names." } }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, + "location": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." + "description": "Azure region for the resource." } }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, + "environmentResourceId": { + "type": "string", "metadata": { - "description": "The type for a container app probe." + "description": "Resource ID of the container app environment." } }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, + "containerRegistryEndpoint": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." + "description": "Container registry endpoint hosting the API image." } }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, + "imageTag": { + "type": "string", "metadata": { - "description": "The type for a container app probe HTTP GET." + "description": "Image tag to deploy." } }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, + "enableScalability": { + "type": "bool", "metadata": { - "description": "The type for a container app probe HTTP GET header." + "description": "Whether additional scale-out should be enabled." } }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The type for a container app probe TCP socket." + "description": "Whether monitoring is enabled." } }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "The scale settings for the Container App." + "description": "Optional. Application Insights connection string." } }, - "scaleRuleType": { + "tags": { "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "The scaling rules for the Container App." + "description": "Tags to apply to the resource." } }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "The type for a volume mount." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "authConfigType": { - "type": "object", + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. App Configuration endpoint for post-bootstrap updates." + } + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-api', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } + } + } + ] + }, + "corsPolicy": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-api.{0}', parameters('solutionSuffix')), 64)]", "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "expressionEvaluationOptions": { + "scope": "inner" }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('containerAppName')]" }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "location": { + "value": "[parameters('location')]" }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "workloadProfileName": { + "value": "Consumption" }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": "[variables('corsPolicy')]" } }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + } + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } }, - "parameters": { - "name": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. Name of the Container App." - } + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." - } + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" }, - "kind": { + "fqdn": { "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "clientCertificateMode": { + "systemAssignedMIPrincipalId": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", "nullable": true, "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + }, + "apiAppFqdn": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.fqdn.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9143297874990358007" + } + }, + "parameters": { + "solutionSuffix": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." + "description": "Unique solution suffix used to derive resource names." } }, - "ingressTransport": { + "location": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." + "description": "Azure region for the resource." } }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, + "environmentResourceId": { + "type": "string", "metadata": { - "description": "Optional. List of container app services bound to the app." + "description": "Resource ID of the container app environment." } }, - "activeRevisionsMode": { + "containerRegistryEndpoint": { "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + "description": "Container registry endpoint hosting the web image." } }, - "environmentResourceId": { + "imageTag": { "type": "string", "metadata": { - "description": "Required. Resource ID of environment." + "description": "Image tag to deploy." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "enableScalability": { + "type": "bool", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Whether additional scale-out should be enabled." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Tags to apply to the resource." } }, "enableTelemetry": { @@ -47082,334 +36024,135 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "User-assigned managed identity resource IDs to attach to the container app." + } + }, + "apiAppFqdn": { + "type": "string", + "metadata": { + "description": "API application FQDN used by the frontend." + } + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-web', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" + } ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + } + }, + "resources": { + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.container-app-web.{0}', parameters('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "ingressExternal": { + "value": true }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "ingressTargetPort": { + "value": 3000 }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "activeRevisionsMode": { + "value": "Single" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "ingressTransport": { + "value": "auto" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "ingressAllowInsecure": { + "value": false }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "scaleSettings": { + "value": "[variables('scaleSettings')]" + }, + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_API_BASE_URL", + "value": "[format('https://{0}', parameters('apiAppFqdn'))]" + }, + { + "name": "APP_WEB_CLIENT_ID", + "value": "" + }, + { + "name": "APP_WEB_AUTHORITY", + "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" + }, + { + "name": "APP_WEB_SCOPE", + "value": "" + }, + { + "name": "APP_API_SCOPE", + "value": "" + }, + { + "name": "APP_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_POST_REDIRECT_URL", + "value": "/" + }, + { + "name": "APP_CONSOLE_LOG_ENABLED", + "value": "false" + } + ] + } + ] } }, "template": { @@ -47420,324 +36163,1845 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "11353975374580271835" + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Name of the container app." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "globalValidation": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "httpSettings": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "identityProviders": { - "type": "object", + "environmentResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Resource ID of the container app environment." + } }, - "login": { + "managedIdentities": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } }, - "platform": { + "scaleSettings": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Full scale settings object." + } }, - "enableTelemetry": { + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." } } }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "Name of the container app." }, - "value": "current" + "value": "[reference('containerApp').outputs.name.value]" }, - "resourceId": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Fully qualified domain name of the container app." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "resourceGroupName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[resourceGroup().name]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } - }, - "dependsOn": [ - "containerApp" - ] + } } }, "outputs": { "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." + "description": "Resource ID of the container app." }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the Container App was deployed into." + "description": "Name of the container app." }, - "value": "[resourceGroup().name]" + "value": "[reference('containerApp').outputs.name.value]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "The name of the Container App." + "description": "Fully qualified domain name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } }, "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmContainerApp_Web": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-web.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('ca-{0}-web', variables('solutionSuffix'))]" + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" }, "location": { "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "workloadProfileName": { - "value": "Consumption" + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" }, - "registries": { - "value": null + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", "tags": { "value": "[parameters('tags')]" }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "ingressExternal": { - "value": true - }, - "ingressTargetPort": { - "value": 3000 - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" - } - } - } - ] - } + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "containers": { + "userAssignedResourceIds": { "value": [ - { - "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_API_BASE_URL", - "value": "[format('https://{0}', reference('avmContainerApp_API').outputs.fqdn.value)]" - }, - { - "name": "APP_WEB_CLIENT_ID", - "value": "" - }, - { - "name": "APP_WEB_AUTHORITY", - "value": "[format('{0}/{1}', environment().authentication.loginEndpoint, tenant().tenantId)]" - }, - { - "name": "APP_WEB_SCOPE", - "value": "" - }, - { - "name": "APP_API_SCOPE", - "value": "" - }, - { - "name": "APP_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_POST_REDIRECT_URL", - "value": "/" - }, - { - "name": "APP_CONSOLE_LOG_ENABLED", - "value": "false" - } - ] - } + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" ] } }, @@ -47749,1318 +38013,2223 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." + "templateHash": "9387175626757048649" + } }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, + "parameters": { + "solutionSuffix": { + "type": "string", "metadata": { - "description": "The type for a service binding." + "description": "Unique solution suffix used to derive resource names." } }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, + "location": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." + "description": "Azure region for the resource." } }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, + "environmentResourceId": { + "type": "string", "metadata": { - "description": "The type for a container app probe." + "description": "Resource ID of the container app environment." } }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, + "containerRegistryEndpoint": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." + "description": "Container registry endpoint hosting the workflow image." } }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, + "imageTag": { + "type": "string", "metadata": { - "description": "The type for a container app probe HTTP GET." + "description": "Image tag to deploy." } }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, + "enableScalability": { + "type": "bool", "metadata": { - "description": "The type for a container app probe HTTP GET header." + "description": "Whether additional scale-out should be enabled." } }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The type for a container app probe TCP socket." + "description": "Whether monitoring is enabled." } }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "The scale settings for the Container App." + "description": "Optional. Application Insights connection string." } }, - "scaleRuleType": { + "tags": { "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "The scaling rules for the Container App." + "description": "Tags to apply to the resource." } }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "The type for a volume mount." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "authConfigType": { - "type": "object", + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. App Configuration endpoint for post-bootstrap updates." + } + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-wkfl', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-workflow.{0}', parameters('solutionSuffix')), 64)]", "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "expressionEvaluationOptions": { + "scope": "inner" }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] + }, + "activeRevisionsMode": { + "value": "Single" }, - "nullable": true + "ingressExternal": { + "value": false + }, + "disableIngress": { + "value": true + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" + } }, - "httpSettings": { - "type": "object", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } + } + } + } }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { + "outputs": { + "resourceId": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "stickySessionsAffinity": { + "name": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" }, - "ingressTransport": { + "fqdn": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." + "description": "Fully qualified domain name of the container app." }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, + "systemAssignedMIPrincipalId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" + "description": "Principal ID of the system-assigned managed identity." }, - "nullable": true, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-processor.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + }, + "appConfigEndpoint": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7070907820525585254" + } + }, + "parameters": { + "solutionSuffix": { + "type": "string", "metadata": { - "description": "Optional. List of container app services bound to the app." + "description": "Unique solution suffix used to derive resource names." } }, - "activeRevisionsMode": { + "location": { "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + "description": "Azure region for the resource." } }, "environmentResourceId": { "type": "string", "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + "description": "Resource ID of the container app environment." } }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", + "containerRegistryEndpoint": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." + "description": "Container registry endpoint hosting the processor image." } }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, + "imageTag": { + "type": "string", "metadata": { - "description": "Optional. The termination grace period for the container app." + "description": "Image tag to deploy." } }, - "initContainersTemplate": { - "type": "array", + "enableScalability": { + "type": "bool", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true + "description": "Whether additional scale-out should be enabled." + } }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The secrets of the Container App." + "description": "Whether monitoring is enabled." } }, - "revisionSuffix": { + "appInsightsConnectionString": { "type": "string", - "nullable": true, + "defaultValue": "", "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "Optional. Application Insights connection string." } }, - "volumes": { - "type": "array", + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "workloadProfileName": { - "type": "string", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. The name of the Container App Auth configs." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false + "containerAppName": "[format('ca-{0}-app', parameters('solutionSuffix'))]", + "containerName": "[format('ca-{0}', parameters('solutionSuffix'))]", + "scaleSettings": "[if(empty(parameters('appConfigEndpoint')), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1)), createObject('maxReplicas', if(parameters('enableScalability'), 3, 2), 'minReplicas', if(parameters('enableScalability'), 2, 1), 'rules', if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())))]" }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.container-app-processor.{0}', parameters('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "containers": { + "value": [ + { + "name": "[variables('containerName')]", + "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessor" + } + ] + } + ] }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "activeRevisionsMode": { + "value": "Single" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "ingressExternal": { + "value": false }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "disableIngress": { + "value": true }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "scaleSettings": { + "value": "[variables('scaleSettings')]" } }, "template": { @@ -49071,305 +40240,1850 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "11353975374580271835" + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Name of the container app." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "globalValidation": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "httpSettings": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "identityProviders": { - "type": "object", + "environmentResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Resource ID of the container app environment." + } }, - "login": { + "managedIdentities": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } }, - "platform": { + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Full scale settings object." + } }, - "enableTelemetry": { + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." } } }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "Name of the container app." }, - "value": "current" + "value": "[reference('containerApp').outputs.name.value]" }, - "resourceId": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Fully qualified domain name of the container app." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "resourceGroupName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[resourceGroup().name]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } - }, - "dependsOn": [ - "containerApp" - ] + } } }, "outputs": { "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." + "description": "Resource ID of the container app." }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the Container App was deployed into." + "description": "Name of the container app." }, - "value": "[resourceGroup().name]" + "value": "[reference('containerApp').outputs.name.value]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "The name of the Container App." + "description": "Fully qualified domain name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } }, "dependsOn": [ - "avmContainerApp_API", - "avmContainerAppEnv", - "avmContainerRegistryReader" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmContainerApp_Workflow": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" }, "location": { "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, - "workloadProfileName": { - "value": "Consumption" + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" }, - "registries": { - "value": null + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", "tags": { "value": "[parameters('tags')]" }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "containers": { + "userAssignedResourceIds": { "value": [ - { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] - } + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" ] }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } + "appConfigEndpoint": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" } }, "template": { @@ -49380,1318 +42094,2294 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." + "templateHash": "17990158768842819361" + } }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, + "parameters": { + "solutionSuffix": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." + "description": "Unique solution suffix used to derive resource names." } }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "environmentResourceId": { + "type": "string", "metadata": { - "description": "The type for a service binding." + "description": "Resource ID of the container app environment." } }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, + "containerRegistryEndpoint": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." + "description": "Container registry endpoint hosting the API image." } }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, + "imageTag": { + "type": "string", "metadata": { - "description": "The type for a container app probe." + "description": "Image tag to deploy." } }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, + "enableScalability": { + "type": "bool", "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." + "description": "Whether additional scale-out should be enabled." } }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The type for a container app probe HTTP GET." + "description": "Whether monitoring is enabled." } }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, + "appInsightsConnectionString": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "The type for a container app probe HTTP GET header." + "description": "Optional. Application Insights connection string." } }, - "containerAppProbeTcpSocketType": { + "tags": { "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "The type for a container app probe TCP socket." + "description": "Tags to apply to the resource." } }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "The scale settings for the Container App." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The scaling rules for the Container App." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "The type for a volume mount." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + }, + "variables": { + "containerAppName": "[format('ca-{0}-api', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", + "rules": [ + { + "name": "http-scaler", + "http": { + "metadata": { + "concurrentRequests": "100" + } } } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } + ] }, - "authConfigType": { - "type": "object", + "corsPolicy": { + "allowedOrigins": [ + "*" + ], + "allowedMethods": [ + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS" + ], + "allowedHeaders": [ + "Authorization", + "Content-Type", + "*" + ] + } + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-api.{0}', parameters('solutionSuffix')), 64)]", "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "expressionEvaluationOptions": { + "scope": "inner" }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('containerAppName')]" }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "location": { + "value": "[parameters('location')]" }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "workloadProfileName": { + "value": "Consumption" }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } + }, + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorAPI" + } + ], + "probes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 + }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ] + } + ] + }, + "scaleSettings": { + "value": "[variables('scaleSettings')]" + }, + "ingressExternal": { + "value": true + }, + "activeRevisionsMode": { + "value": "Single" + }, + "ingressTransport": { + "value": "auto" + }, + "ingressAllowInsecure": { + "value": false + }, + "corsPolicy": { + "value": "[variables('corsPolicy')]" } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "11353975374580271835" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app environment." + } + }, + "managedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Full scale settings object." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." + } + } + }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, + "resources": { + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" + } + } } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the container app." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "Fully qualified domain name of the container app." + }, + "value": "[reference('containerApp').outputs.fqdn.value]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Principal ID of the system-assigned managed identity." + }, + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } } - }, - "customDomains": { - "type": "array", + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." + "description": "Resource ID of the container app." }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "ipSecurityRestrictions": { - "type": "array", + "name": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." + "description": "Name of the container app." }, - "nullable": true + "value": "[reference('containerApp').outputs.name.value]" }, - "traffic": { - "type": "array", + "fqdn": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + "description": "Fully qualified domain name of the container app." }, - "nullable": true + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "dapr": { - "type": "object", + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." + "description": "Principal ID of the system-assigned managed identity." }, - "nullable": true - }, - "identitySettings": { - "type": "array", + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.container-app-workflow.update.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionSuffix": { + "value": "[variables('solutionSuffix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + }, + "containerRegistryEndpoint": { + "value": "[parameters('containerRegistryEndpoint')]" + }, + "imageTag": { + "value": "[parameters('imageTag')]" + }, + "enableScalability": { + "value": "[parameters('enableScalability')]" + }, + "enableMonitoring": { + "value": "[parameters('enableMonitoring')]" + }, + "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "userAssignedResourceIds": { + "value": [ + "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + ] + }, + "appConfigEndpoint": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "9387175626757048649" + } + }, + "parameters": { + "solutionSuffix": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true + "description": "Unique solution suffix used to derive resource names." + } }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, + "location": { + "type": "string", "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." + "description": "Azure region for the resource." } }, - "runtime": { - "type": "object", + "environmentResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true + "description": "Resource ID of the container app environment." + } }, - "containers": { - "type": "array", + "containerRegistryEndpoint": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." + "description": "Container registry endpoint hosting the workflow image." } }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, + "imageTag": { + "type": "string", "metadata": { - "description": "Optional. The termination grace period for the container app." + "description": "Image tag to deploy." } }, - "initContainersTemplate": { - "type": "array", + "enableScalability": { + "type": "bool", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true + "description": "Whether additional scale-out should be enabled." + } }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, + "enableMonitoring": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The secrets of the Container App." + "description": "Whether monitoring is enabled." } }, - "revisionSuffix": { + "appInsightsConnectionString": { "type": "string", - "nullable": true, + "defaultValue": "", "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "Optional. Application Insights connection string." } }, - "volumes": { - "type": "array", + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "workloadProfileName": { - "type": "string", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, + "userAssignedResourceIds": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. The name of the Container App Auth configs." + "description": "User-assigned managed identity resource IDs to attach to the container app." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "appConfigEndpoint": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. App Configuration endpoint for post-bootstrap updates." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false + "containerAppName": "[format('ca-{0}-wkfl', parameters('solutionSuffix'))]", + "scaleSettings": { + "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", + "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" + } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('module.container-app-workflow.{0}', parameters('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { - "value": "[parameters('name')]" + "name": { + "value": "[variables('containerAppName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "workloadProfileName": { + "value": "Consumption" }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": "[parameters('userAssignedResourceIds')]" + } }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "containers": { + "value": [ + { + "name": "[variables('containerAppName')]", + "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "resources": { + "cpu": 4, + "memory": "8.0Gi" + }, + "env": [ + { + "name": "APP_CONFIG_ENDPOINT", + "value": "[parameters('appConfigEndpoint')]" + }, + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_LOGGING_LEVEL", + "value": "INFO" + }, + { + "name": "AZURE_PACKAGE_LOGGING_LEVEL", + "value": "WARNING" + }, + { + "name": "AZURE_LOGGING_PACKAGES", + "value": "" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[if(parameters('enableMonitoring'), parameters('appInsightsConnectionString'), '')]" + }, + { + "name": "OTEL_SERVICE_NAME", + "value": "ContentProcessorWorkflow" + } + ] + } + ] }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "activeRevisionsMode": { + "value": "Single" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "ingressExternal": { + "value": false }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "disableIngress": { + "value": true }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "scaleSettings": { + "value": "[variables('scaleSettings')]" } }, "template": { @@ -50702,214 +44392,1809 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "templateHash": "11353975374580271835" + } }, "parameters": { - "containerAppName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "Name of the container app." } }, - "encryptionSettings": { - "type": "object", + "location": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Azure region for the resource." + } }, - "globalValidation": { + "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true + "description": "Tags to apply to the resource." + } }, - "httpSettings": { - "type": "object", + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Enable/Disable usage telemetry for module." + } }, - "identityProviders": { - "type": "object", + "environmentResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Resource ID of the container app environment." + } }, - "login": { + "managedIdentities": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Managed identity configuration." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Container registry configuration." + } + }, + "containers": { + "type": "array", + "metadata": { + "description": "Container definitions for the container app." + } }, - "platform": { + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "metadata": { + "description": "Optional. Active revisions mode." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Minimum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Maximum replica count alias used when scaleSettings is not supplied." + } + }, + "scaleSettings": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "Optional. Full scale settings object." + } }, - "enableTelemetry": { + "ingressTargetPort": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Ingress target port." + } + }, + "ingressExternal": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Whether ingress is external." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Ingress transport setting." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Secret definitions for the container app." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether ingress is disabled." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether insecure ingress traffic is allowed." + } + }, + "corsPolicy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. CORS policy configuration." } } }, + "variables": { + "resolvedScaleSettings": "[if(not(empty(parameters('scaleSettings'))), parameters('scaleSettings'), if(or(not(equals(parameters('scaleMinReplicas'), -1)), not(equals(parameters('scaleMaxReplicas'), -1))), union(if(not(equals(parameters('scaleMinReplicas'), -1)), createObject('minReplicas', parameters('scaleMinReplicas')), createObject()), if(not(equals(parameters('scaleMaxReplicas'), -1)), createObject('maxReplicas', parameters('scaleMaxReplicas')), createObject())), null()))]" + }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "containerApp": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[take(format('avm.res.app.container-app.{0}', parameters('name')), 64)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "environmentResourceId": { + "value": "[parameters('environmentResourceId')]" + }, + "managedIdentities": "[if(empty(parameters('managedIdentities')), createObject('value', null()), createObject('value', parameters('managedIdentities')))]", + "registries": "[if(not(empty(parameters('registries'))), createObject('value', parameters('registries')), createObject('value', null()))]", + "containers": { + "value": "[parameters('containers')]" + }, + "activeRevisionsMode": "[if(not(empty(parameters('activeRevisionsMode'))), createObject('value', parameters('activeRevisionsMode')), createObject('value', null()))]", + "scaleSettings": { + "value": "[variables('resolvedScaleSettings')]" + }, + "ingressTargetPort": "[if(not(equals(parameters('ingressTargetPort'), -1)), createObject('value', parameters('ingressTargetPort')), createObject('value', null()))]", + "ingressExternal": { + "value": "[parameters('ingressExternal')]" + }, + "ingressTransport": "[if(not(empty(parameters('ingressTransport'))), createObject('value', parameters('ingressTransport')), createObject('value', null()))]", + "secrets": "[if(not(empty(parameters('secrets'))), createObject('value', parameters('secrets')), createObject('value', null()))]", + "workloadProfileName": "[if(not(empty(parameters('workloadProfileName'))), createObject('value', parameters('workloadProfileName')), createObject('value', null()))]", + "disableIngress": { + "value": "[parameters('disableIngress')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": "[if(empty(parameters('corsPolicy')), createObject('value', null()), createObject('value', parameters('corsPolicy')))]" + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12626366001403616495" + }, + "name": "Container Apps", + "description": "This module deploys a Container App." + }, + "definitions": { + "ingressPortMappingType": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an ingress port mapping." + } + }, + "serviceBindingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + }, + "metadata": { + "description": "The type for a service binding." + } + }, + "environmentVarType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an environment variable." + } + }, + "containerAppProbeType": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGetType", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocketType", + "nullable": true, + "metadata": { + "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + }, + "metadata": { + "description": "The type for a container app probe." + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a CORS policy." + } + }, + "containerAppProbeHttpGetType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET." + } + }, + "containerAppProbeHttpGetHeadersItemType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + }, + "metadata": { + "description": "The type for a container app probe HTTP GET header." + } + }, + "containerAppProbeTcpSocketType": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + }, + "metadata": { + "description": "The type for a container app probe TCP socket." + } + }, + "scaleType": { + "type": "object", + "properties": { + "maxReplicas": { + "type": "int", + "metadata": { + "description": "Required. The maximum number of replicas." + } + }, + "minReplicas": { + "type": "int", + "metadata": { + "description": "Required. The minimum number of replicas." + } + }, + "cooldownPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The cooldown period in seconds." + } + }, + "pollingInterval": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The polling interval in seconds." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/scaleRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The scaling rules." + } + } + }, + "metadata": { + "description": "The scale settings for the Container App." + } + }, + "scaleRuleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scaling rule." + } + }, + "custom": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The custom scaling rule." + } + }, + "azureQueue": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Queue based scaling rule." + } + }, + "http": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The HTTP requests based scaling rule." + } + }, + "tcp": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The TCP based scaling rule." + } + } + }, + "metadata": { + "description": "The scaling rules for the Container App." + } + }, + "volumeMountType": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + }, + "metadata": { + "description": "The type for a volume mount." + } + }, + "secretType": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." + } + }, + "keyVaultUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the container app secret." + } + }, + "value": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret." + } + }, + "authConfigType": { + "type": "object", + "properties": { + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the container app's authentication configuration." + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "containerapps", + "allowedValues": [ + "containerapps", + "workflowapp", + "functionapp" + ], + "metadata": { + "description": "Optional. Metadata used to render different experiences for resources of the same type." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" + }, + "description": "Optional. Dev ContainerApp service type." + }, + "nullable": true + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMappingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleSettings": { + "$ref": "#/definitions/scaleType", + "defaultValue": { + "maxReplicas": 10, + "minReplicas": 3 + }, + "metadata": { + "description": "Optional. The scaling settings of the service." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBindingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registries": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" + }, + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "customDomains": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" + }, + "description": "Optional. Custom domain bindings for Container App hostnames." + }, + "nullable": true + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" + }, + "description": "Optional. Rules to restrict incoming IP address." + }, + "nullable": true + }, + "traffic": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" + }, + "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." + }, + "nullable": true + }, + "dapr": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" + }, + "description": "Optional. Dapr configuration for the Container App." + }, + "nullable": true + }, + "identitySettings": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" + }, + "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." + }, + "nullable": true + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "runtime": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" + }, + "description": "Optional. Runtime configuration for the Container App." + }, + "nullable": true + }, + "containers": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" + }, + "description": "Required. List of container definitions for the Container App." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The termination grace period for the container app." + } + }, + "initContainersTemplate": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" + }, + "description": "Optional. List of specialized containers that run before app containers." + }, + "nullable": true + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" + }, + "description": "Optional. List of volume definitions for the Container App." + }, + "nullable": true + }, + "workloadProfileName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + }, + "authConfig": { + "$ref": "#/definitions/authConfigType", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Container App Auth configs." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "workloadProfileName": "[parameters('workloadProfileName')]", + "template": { + "containers": "[parameters('containers')]", + "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", + "initContainers": "[parameters('initContainersTemplate')]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": "[parameters('scaleSettings')]", + "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", + "volumes": "[parameters('volumes')]" + }, + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[parameters('dapr')]", + "identitySettings": "[parameters('identitySettings')]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[parameters('registries')]", + "secrets": "[parameters('secrets')]", + "runtime": "[parameters('runtime')]" + } + } + }, + "containerApp_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerApp_diagnosticSettings": { + "copy": { + "name": "containerApp_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "containerApp" + ] + }, + "containerAppAuthConfigs": { + "condition": "[not(empty(parameters('authConfig')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerAppName": { + "value": "[parameters('name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "encryptionSettings": { + "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + }, + "globalValidation": { + "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + }, + "httpSettings": { + "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + }, + "identityProviders": { + "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + }, + "login": { + "value": "[tryGet(parameters('authConfig'), 'login')]" + }, + "platform": { + "value": "[tryGet(parameters('authConfig'), 'platform')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "4649255393182983719" + }, + "name": "Container App Auth Configs", + "description": "This module deploys Container App Auth Configs." + }, + "parameters": { + "containerAppName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + } + }, + "encryptionSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + }, + "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "globalValidation": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + }, + "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + }, + "nullable": true + }, + "httpSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + }, + "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "identityProviders": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + }, + "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "login": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + }, + "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "platform": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + }, + "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerApp": { + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2026-01-01", + "name": "[parameters('containerAppName')]" + }, + "containerAppAuthConfigs": { + "type": "Microsoft.App/containerApps/authConfigs", + "apiVersion": "2026-01-01", + "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "properties": { + "encryptionSettings": "[parameters('encryptionSettings')]", + "globalValidation": "[parameters('globalValidation')]", + "httpSettings": "[parameters('httpSettings')]", + "identityProviders": "[parameters('identityProviders')]", + "login": "[parameters('login')]", + "platform": "[parameters('platform')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the set of Container App Auth configs." + }, + "value": "current" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the set of Container App Auth configs." + }, + "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group containing the set of Container App Auth configs." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "containerApp" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2026-01-01', 'full').location]" } } } } - }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } } }, "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the container app." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "Name of the container app." }, - "value": "current" + "value": "[reference('containerApp').outputs.name.value]" }, - "resourceId": { + "fqdn": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "Fully qualified domain name of the container app." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, - "resourceGroupName": { + "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[resourceGroup().name]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } - }, - "dependsOn": [ - "containerApp" - ] + } } }, "outputs": { "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." + "description": "Resource ID of the container app." }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + "value": "[reference('containerApp').outputs.resourceId.value]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the Container App was deployed into." + "description": "Name of the container app." }, - "value": "[resourceGroup().name]" + "value": "[reference('containerApp').outputs.name.value]" }, - "name": { + "fqdn": { "type": "string", "metadata": { - "description": "The name of the Container App." + "description": "Fully qualified domain name of the container app." }, - "value": "[parameters('name')]" + "value": "[reference('containerApp').outputs.fqdn.value]" }, "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "description": "Principal ID of the system-assigned managed identity." }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" } } } }, "dependsOn": [ - "applicationInsights", - "avmContainerAppEnv", - "avmContainerRegistryReader" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmCosmosDB": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.document-db.database-account.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -50917,59 +46202,113 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" + "value": "[format('aif-{0}', variables('solutionSuffix'))]" + }, + "projectName": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "projectDescription": { + "value": "[format('proj-{0}', variables('solutionSuffix'))]" + }, + "existingFoundryProjectResourceId": { + "value": "[variables('existingProjectResourceId')]" }, "location": { - "value": "[parameters('location')]" + "value": "[parameters('azureAiServiceLocation')]" }, - "mongodbDatabases": { - "value": [ - { - "name": "default", - "tag": "default database" - } - ] + "sku": { + "value": "S0" }, - "tags": { - "value": "[parameters('tags')]" + "allowProjectManagement": { + "value": true }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "managedIdentities": { + "value": { + "systemAssigned": true + } }, - "databaseAccountOfferType": { - "value": "Standard" + "kind": { + "value": "AIServices" }, - "enableAutomaticFailover": { - "value": false + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('azureAiServiceLocation')]" + } }, - "serverVersion": { - "value": "7.0" + "customSubDomainName": { + "value": "[format('aif-{0}', variables('solutionSuffix'))]" }, - "capabilitiesToAdd": { + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value))), createObject('value', null()))]", + "roleAssignments": { "value": [ - "EnableMongo" + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services OpenAI User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Azure AI Developer", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "roleDefinitionIdOrName": "Cognitive Services User", + "principalType": "ServicePrincipal" + } ] }, - "defaultConsistencyLevel": { - "value": "Session" - }, - "maxIntervalInSeconds": { - "value": 5 + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]" + } }, - "maxStalenessPrefix": { - "value": 100 + "disableLocalAuth": { + "value": true }, - "zoneRedundant": { - "value": false + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "networkRestrictions": { - "value": { - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]", - "ipRules": [], - "virtualNetworkRules": [] - } + "deployments": { + "value": [ + { + "name": "[parameters('gptModelName')]", + "model": { + "format": "OpenAI", + "name": "[parameters('gptModelName')]", + "version": "[parameters('gptModelVersion')]" + }, + "sku": { + "name": "[parameters('deploymentType')]", + "capacity": "[parameters('gptDeploymentCapacity')]" + }, + "raiPolicyName": "Microsoft.Default" + } + ] }, - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-cosmosdb-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-cosmosdb-{0}', variables('solutionSuffix')), 'privateEndpointResourceId', reference('virtualNetwork').outputs.resourceId.value, 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'cosmosdb-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)).outputs.resourceId.value))), 'service', 'MongoDB', 'subnetResourceId', reference('virtualNetwork').outputs.backendSubnetResourceId.value))), createObject('value', createArray()))]" + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -50978,11 +46317,11 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1772014800591596213" + "version": "0.42.1.51946", + "templateHash": "18161259334146424275" }, - "name": "Azure Cosmos DB account", - "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." + "name": "Cognitive Services", + "description": "This module deploys a Cognitive Service." }, "definitions": { "privateEndpointOutputType": { @@ -50998,653 +46337,206 @@ "type": "string", "metadata": { "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group ID for the private endpoint group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses for the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "failoverLocationType": { - "type": "object", - "properties": { - "failoverPriority": { - "type": "int", - "metadata": { - "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." - } - }, - "isZoneRedundant": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." - } - }, - "locationName": { - "type": "string", - "metadata": { - "description": "Required. The name of the region." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the failover location." - } - }, - "sqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." - } - }, - "sqlRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of data actions that are allowed." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." - } - }, - "assignments": { - "type": "array", - "items": { - "$ref": "#/definitions/nestedSqlRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." - } - }, - "networkRestrictionType": { - "type": "object", - "properties": { - "ipRules": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." - } - }, - "networkAclBypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." - } - }, - "publicNetworkAccess": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." - } - }, - "virtualNetworkRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of a subnet." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." - } - }, - "networkAclBypassResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network restriction." - } - }, - "gremlinDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin database resource." - }, - "nullable": true - }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a gremlin databae." - } - }, - "mongoDbType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "items": { - "$ref": "#/definitions/collectionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "autoscaleSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" - }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." - }, - "nullable": true - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a mongo databae." - } - }, - "sqlDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a sql database." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" - }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "maxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a table." - } - }, - "cassandraStandaloneRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." - } - }, - "cassandraRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role-based access control definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." - } - }, - "notDataActions": { - "type": "array", - "items": { - "type": "string" - }, + } + }, + "groupId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." + "description": "The group Id for the private endpoint Group." } }, - "assignableScopes": { + "customDnsConfigs": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } }, - "nullable": true, "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." + "description": "The custom DNS configurations of the private endpoint." } }, - "assignments": { + "networkInterfaceResourceIds": { "type": "array", "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" + "type": "string" }, - "nullable": true, "metadata": { - "description": "Optional. An array of role-based access control assignments to be created for the definition." + "description": "The IDs of the network interfaces associated with the private endpoint." } } }, "metadata": { "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." + "description": "The type for the private endpoint output." } }, - "cassandraKeyspaceType": { + "deploymentType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the Cassandra keyspace." + "description": "Optional. Specify the name of cognitive service account deployment." } }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraTableType" + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } }, - "nullable": true, "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + "description": "Required. Properties of Cognitive Services account deployment model." } }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraViewType" + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } }, "nullable": true, "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + "description": "Optional. The resource model definition representing SKU." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "raiPolicyName": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + "description": "Optional. The name of RAI policy." } }, - "throughput": { - "type": "int", + "versionUpgradeOption": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra keyspace resource." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an Azure Cosmos DB Cassandra keyspace." - } - }, - "defaultIdentityType": { - "type": "object", - "discriminator": { - "propertyName": "name", - "mapping": { - "FirstPartyIdentity": { - "$ref": "#/definitions/defaultIdentityFirstPartyType" - }, - "SystemAssignedIdentity": { - "$ref": "#/definitions/defaultIdentitySystemAssignedType" - }, - "UserAssignedIdentity": { - "$ref": "#/definitions/defaultIdentityUserAssignedType" + "description": "Optional. The version upgrade option." } } }, "metadata": { "__bicep_export!": true, - "description": "The type for the default identity." + "description": "The type for a cognitive services account deployment." } }, - "defaultIdentityFirstPartyType": { + "endpointType": { "type": "object", "properties": { "name": { "type": "string", - "allowedValues": [ - "FirstPartyIdentity" - ], + "nullable": true, "metadata": { - "description": "Required. The type of default identity to use." + "description": "Type of the endpoint." } - } - } - }, - "defaultIdentitySystemAssignedType": { - "type": "object", - "properties": { - "name": { + }, + "endpoint": { "type": "string", - "allowedValues": [ - "SystemAssignedIdentity" - ], + "nullable": true, "metadata": { - "description": "Required. The type of default identity to use." + "description": "The endpoint URI." } } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." } }, - "defaultIdentityUserAssignedType": { + "secretsExportConfigurationType": { "type": "object", "properties": { - "name": { + "keyVaultResourceId": { "type": "string", - "allowedValues": [ - "UserAssignedIdentity" - ], "metadata": { - "description": "Required. The type of default identity to use." + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." } }, - "resourceId": { + "accessKey2Name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The resource ID of the user assigned identity to use as the default identity." + "description": "Optional. The name for the accessKey2 secret to create." } } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." } }, "_1.privateEndpointCustomDnsConfigType": { @@ -51756,330 +46648,96 @@ } } }, - "cassandraRoleAssignmentType": { + "_1.secretSetOutputType": { "type": "object", "properties": { - "name": { + "secretResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The unique identifier of the role assignment." + "description": "The resourceId of the exported secret." } }, - "principalId": { + "secretUri": { "type": "string", "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." + "description": "The secret URI of the exported secret." } }, - "scope": { + "secretUriWithVersion": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + "description": "The secret URI with version of the exported secret." } } }, "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", "__bicep_imported_from!": { - "sourceTemplate": "cassandra-role-definition/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "cassandraTableType": { + "aiProjectOutputType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the table." - } - }, - "schema": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the table." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the table." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Analytical TTL for the table." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "description": "Required. Name of the AI project." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." - } - } - }, - "metadata": { - "description": "The type of a Cassandra table.", - "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "tableType" - } - } - }, - "cassandraViewType": { - "type": "object", - "properties": { - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. Name of the view." + "description": "Required. Resource ID of the AI project." } }, - "viewDefinition": { + "apiEndpoint": { "type": "string", "metadata": { - "description": "Required. View definition (CQL statement)." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags for the view." - }, - "nullable": true - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + "description": "Required. API endpoint for the AI project." } } }, "metadata": { - "description": "The type of a Cassandra view (materialized view).", + "description": "Output type representing AI project information.", "__bicep_imported_from!": { - "sourceTemplate": "cassandra-keyspace/main.bicep", - "originalIdentifier": "viewType" + "sourceTemplate": "modules/project.bicep" } } }, - "collectionType": { + "customerManagedKeyType": { "type": "object", "properties": { - "name": { + "keyVaultResourceId": { "type": "string", "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." } }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, - "metadata": { - "description": "The type of a collection.", - "__bicep_imported_from!": { - "sourceTemplate": "mongodb-database/main.bicep" - } - } - }, - "containerType": { - "type": "object", - "properties": { - "name": { + "keyName": { "type": "string", "metadata": { - "description": "Required. Name of the container." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" - }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + "description": "Required. The name of the customer managed key to use for encryption." } }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" - }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - }, - "nullable": true - }, - "kind": { + "keyVersion": { "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], "nullable": true, "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - } - }, - "metadata": { - "description": "The type of a container.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-database/main.bicep" - } - } - }, - "customerManagedKeyAndVaultOnlyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." } }, - "keyName": { + "userAssignedIdentityResourceId": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." } } }, "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", "__bicep_imported_from!": { "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } @@ -52207,53 +46865,6 @@ } } }, - "graphType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true - }, - "partitionKeyPaths": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true - } - }, - "metadata": { - "description": "The type of a graph.", - "__bicep_imported_from!": { - "sourceTemplate": "gremlin-database/main.bicep" - } - } - }, "lockType": { "type": "object", "properties": { @@ -52319,53 +46930,21 @@ } } }, - "nestedSqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "description": "The type for the SQL Role Assignments.", - "__bicep_imported_from!": { - "sourceTemplate": "sql-role-definition/main.bicep", - "originalIdentifier": "sqlRoleAssignmentType" - } - } - }, - "privateEndpointMultiServiceType": { + "privateEndpointSingleServiceType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private endpoint." + "description": "Optional. The name of the Private Endpoint." } }, "location": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The location to deploy the private endpoint to." + "description": "Optional. The location to deploy the Private Endpoint to." } }, "privateLinkServiceConnectionName": { @@ -52377,8 +46956,9 @@ }, "service": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." } }, "subnetResourceId": { @@ -52398,7 +46978,7 @@ "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", "nullable": true, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." } }, "isManualConnection": { @@ -52433,7 +47013,7 @@ }, "nullable": true, "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." } }, "applicationSecurityGroupResourceIds": { @@ -52443,14 +47023,14 @@ }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." } }, "customNetworkInterfaceName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." } }, "lock": { @@ -52477,7 +47057,7 @@ "__bicep_resource_derived_type!": { "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." } }, "enableTelemetry": { @@ -52489,7 +47069,7 @@ } }, "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", "__bicep_imported_from!": { "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } @@ -52569,218 +47149,155 @@ "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the account." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Defaults to the current resource group scope location. Location for all resources." - } }, - "tags": { + "secretsOutputType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the resource." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "databaseAccountOfferType": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard" - ], - "metadata": { - "description": "Optional. The offer type for the account. Defaults to \"Standard\"." - } - }, - "failoverLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/failoverLocationType" + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } }, - "nullable": true, - "metadata": { - "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } - }, - "defaultConsistencyLevel": { + } + }, + "parameters": { + "name": { "type": "string", - "defaultValue": "Session", - "allowedValues": [ - "Eventual", - "ConsistentPrefix", - "Session", - "BoundedStaleness", - "Strong" - ], - "metadata": { - "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." - } - }, - "disableLocalAuthentication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." - } - }, - "enableAnalyticalStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." - } - }, - "enableAutomaticFailover": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable automatic failover for regions. Defaults to true." - } - }, - "enableFreeTier": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." - } - }, - "enableMultipleWriteLocations": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." + "description": "Required. The name of Cognitive Services account." } }, - "disableKeyBasedMetadataWriteAccess": { - "type": "bool", - "defaultValue": true, + "projectName": { + "type": "string", "metadata": { - "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." + "description": "Optional: Name for the project which needs to be created." } }, - "maxStalenessPrefix": { - "type": "int", - "defaultValue": 100000, - "minValue": 1, - "maxValue": 2147483647, + "projectDescription": { + "type": "string", "metadata": { - "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." + "description": "Optional: Description for the project which needs to be created." } }, - "maxIntervalInSeconds": { - "type": "int", - "defaultValue": 300, - "minValue": 5, - "maxValue": 86400, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "" + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], "metadata": { - "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." } }, - "serverVersion": { + "sku": { "type": "string", - "defaultValue": "4.2", + "defaultValue": "S0", "allowedValues": [ - "3.2", - "3.6", - "4.0", - "4.2", - "5.0", - "6.0", - "7.0" + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" ], "metadata": { - "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." } }, - "sqlDatabases": { + "diagnosticSettings": { "type": "array", "items": { - "$ref": "#/definitions/sqlDatabaseType" + "$ref": "#/definitions/diagnosticSettingFullType" }, "nullable": true, "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." + "description": "Optional. The diagnostic settings of the service." } }, - "mongodbDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/mongoDbType" - }, + "publicNetworkAccess": { + "type": "string", "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." } }, - "gremlinDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/gremlinDatabaseType" - }, + "customSubDomainName": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." } }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, + "networkAcls": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." + "description": "Optional. A collection of rules governing the accessibility from specific network locations." } }, - "cassandraKeyspaces": { + "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/cassandraKeyspaceType" + "$ref": "#/definitions/privateEndpointSingleServiceType" }, "nullable": true, "metadata": { - "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "totalThroughputLimit": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, "lock": { @@ -52797,269 +47314,183 @@ }, "nullable": true, "metadata": { - "description": "Optional. An array of control plane Azure role-based access control assignments." + "description": "Optional. Array of role assignments to create." } }, - "sqlRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleDefinitionType" - }, - "nullable": true, + "processorPrincipalId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." + "description": "Optional. Principal ID of the processor container app managed identity." } }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, + "workflowPrincipalId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." + "description": "Optional. Principal ID of the workflow container app managed identity." } }, - "cassandraRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleDefinitionType" - }, + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." + "description": "Optional. Tags of the resource." } }, - "cassandraRoleAssignments": { + "allowedFqdnList": { "type": "array", - "items": { - "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" - }, "nullable": true, "metadata": { - "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." + "description": "Optional. List of allowed FQDN." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, + "apiProperties": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. The diagnostic settings for the service." + "description": "Optional. The API properties for special APIs." } }, - "capabilitiesToAdd": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "allowedValues": [ - "EnableCassandra", - "EnableTable", - "EnableGremlin", - "EnableMongo", - "DisableRateLimitingResponses", - "EnableServerless", - "EnableNoSQLVectorSearch", - "EnableNoSQLFullTextSearch", - "EnableMaterializedViews", - "DeleteAllItemsByPartitionKey" - ], + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." } }, - "backupPolicyType": { - "type": "string", - "defaultValue": "Continuous", - "allowedValues": [ - "Periodic", - "Continuous" - ], + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, "metadata": { - "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." + "description": "Optional. The customer managed key definition." } }, - "backupPolicyContinuousTier": { - "type": "string", - "defaultValue": "Continuous30Days", - "allowedValues": [ - "Continuous30Days", - "Continuous7Days" - ], + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." + "description": "Optional. The flag to enable dynamic throttling." } }, - "backupIntervalInMinutes": { - "type": "int", - "defaultValue": 240, - "minValue": 60, - "maxValue": 1440, + "migrationToken": { + "type": "securestring", + "nullable": true, "metadata": { - "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." + "description": "Optional. Resource migration token." } }, - "backupRetentionIntervalInHours": { - "type": "int", - "defaultValue": 8, - "minValue": 2, - "maxValue": 720, + "restore": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." } }, - "backupStorageRedundancy": { - "type": "string", - "defaultValue": "Local", - "allowedValues": [ - "Geo", - "Local", - "Zone" - ], + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." + "description": "Optional. Restrict outbound network access." } }, - "privateEndpoints": { + "userOwnedStorage": { "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, "nullable": true, "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." - } - }, - "networkRestrictions": { - "$ref": "#/definitions/networkRestrictionType", - "defaultValue": { - "ipRules": [], - "virtualNetworkRules": [], - "publicNetworkAccess": "Disabled" - }, - "metadata": { - "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." + "description": "Optional. The storage accounts for this resource." } }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "Tls12", - "allowedValues": [ - "Tls12" - ], + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { - "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." + "description": "Optional. The managed identity definition for this resource." } }, - "enableBurstCapacity": { + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "enableCassandraConnector": { - "type": "bool", - "defaultValue": false, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, "metadata": { - "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." + "description": "Optional. Array of deployments about cognitive service accounts to create." } }, - "enablePartitionMerge": { - "type": "bool", - "defaultValue": false, + "gptModelName": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." + "description": "Optional. GPT model name used to build the default deployment." } }, - "enablePerRegionPerPartitionAutoscale": { - "type": "bool", - "defaultValue": false, + "gptModelVersion": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." + "description": "Optional. GPT model version used to build the default deployment." } }, - "analyticalStorageConfiguration": { - "type": "object", + "gptDeploymentSkuName": { + "type": "string", + "defaultValue": "", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" - }, - "description": "Optional. Analytical storage specific properties." - }, - "nullable": true + "description": "Optional. Deployment SKU name for the default GPT deployment." + } }, - "cors": { - "type": "array", + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": -1, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" - }, - "description": "Optional. The CORS policy for the Cosmos DB database account." - }, - "nullable": true + "description": "Optional. Deployment capacity for the default GPT deployment." + } }, - "defaultIdentity": { - "$ref": "#/definitions/defaultIdentityType", - "defaultValue": { - "name": "FirstPartyIdentity" - }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, "metadata": { - "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." } }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", + "allowProjectManagement": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." + "description": "Optional. Enable/Disable project management feature for AI Foundry." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInControlPlaneRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", - "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", - "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", - "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", - "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + "resolvedRoleAssignments": "[if(not(empty(coalesce(parameters('roleAssignments'), createArray()))), parameters('roleAssignments'), concat(if(not(empty(parameters('processorPrincipalId'))), createArray(createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services OpenAI User', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', 'Azure AI Developer', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('processorPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services User', 'principalType', 'ServicePrincipal')), createArray()), if(not(empty(parameters('workflowPrincipalId'))), createArray(createObject('principalId', parameters('workflowPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services OpenAI User', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('workflowPrincipalId'), 'roleDefinitionIdOrName', 'Azure AI Developer', 'principalType', 'ServicePrincipal'), createObject('principalId', parameters('workflowPrincipalId'), 'roleDefinitionIdOrName', 'Cognitive Services User', 'principalType', 'ServicePrincipal')), createArray())))]", + "resolvedDeployments": "[if(not(empty(coalesce(parameters('deployments'), createArray()))), parameters('deployments'), if(and(and(and(not(empty(parameters('gptModelName'))), not(empty(parameters('gptModelVersion')))), not(empty(parameters('gptDeploymentSkuName')))), greater(parameters('gptDeploymentCapacity'), 0)), createArray(createObject('name', parameters('gptModelName'), 'model', createObject('format', 'OpenAI', 'name', parameters('gptModelName'), 'version', parameters('gptModelVersion')), 'sku', createObject('name', parameters('gptDeploymentSkuName'), 'capacity', parameters('gptDeploymentCapacity')), 'raiPolicyName', 'Microsoft.Default')), createArray()))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", + "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" }, "resources": { "cMKKeyVault::cMKKey": { - "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", "existing": true, "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -53076,132 +47507,111 @@ } }, "cMKKeyVault": { - "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", "existing": true, "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", - "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", - "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" + "apiVersion": "2026-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" }, - "databaseAccount": { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2025-01-31-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "cognitiveServiceNew": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", - "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", - "dependsOn": [ - "cMKKeyVault::cMKKey" - ] - }, - "databaseAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_diagnosticSettings": { - "copy": { - "name": "databaseAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "sku": { + "name": "[parameters('sku')]" }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "allowProjectManagement": "[parameters('allowProjectManagement')]", + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" }, "dependsOn": [ - "databaseAccount" + "cMKKeyVault", + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" ] }, - "databaseAccount_roleAssignments": { - "copy": { - "name": "databaseAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "databaseAccount" - ] + "cognitiveServiceExisting": { + "condition": "[variables('useExistingService')]", + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[variables('existingCognitiveServiceDetails')[8]]" }, - "databaseAccount_sqlDatabases": { - "copy": { - "name": "databaseAccount_sqlDatabases", - "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" - }, + "cognitive_service_dependencies": { + "condition": "[not(variables('useExistingService'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", + "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, "name": { - "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" + "value": "[parameters('name')]" }, - "containers": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" + "location": { + "value": "[parameters('location')]" }, - "throughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" + "deployments": { + "value": "[variables('resolvedDeployments')]" }, - "databaseAccountName": { - "value": "[parameters('name')]" + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[variables('resolvedRoleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -53211,698 +47621,1097 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "3972888645334640168" + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } }, - "name": "DocumentDB Database Account SQL Databases", - "description": "This module deploys a SQL Database in a CosmosDB Account." - }, - "definitions": { - "containerType": { + "endpointType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the container." + "description": "Type of the endpoint." } }, - "analyticalStorageTtl": { - "type": "int", + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + "description": "Optional. Array of role assignments to create." } }, - "conflictResolutionPolicy": { + "tags": { "type": "object", + "nullable": true, "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } }, - "defaultTtl": { - "type": "int", + "enableTelemetry": { + "type": "bool", "nullable": true, - "minValue": -1, - "maxValue": 2147483647, "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "throughput": { - "type": "int", + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, + "roleDefinitionIdOrName": { + "type": "string", "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "tags": { - "type": "object", + "principalId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + "description": "Optional. The principal type of the assigned principal ID." } }, - "indexingPolicy": { - "type": "object", + "description": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true + "description": "Optional. The description of the role assignment." + } }, - "uniqueKeyPolicyKeys": { - "type": "array", + "condition": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" - }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - }, - "nullable": true + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } }, - "kind": { + "conditionVersion": { "type": "string", "allowedValues": [ - "Hash", - "MultiHash" + "2.0" ], "nullable": true, "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + "description": "Optional. Version of the condition." } }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], + "delegatedManagedIdentityResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a container." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. The name of Cognitive Services account." } }, - "name": { + "sku": { "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], "metadata": { - "description": "Required. Name of the SQL database ." + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." } }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "nullable": true, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." + "description": "Optional. Location for all Resources." } }, - "throughput": { - "type": "int", + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. Tags of the resource." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, "nullable": true, "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + "description": "Optional. Array of deployments about cognitive service accounts to create." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL database resource." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "container": { - "copy": { - "name": "container", - "count": "[length(coalesce(parameters('containers'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "sqlDatabaseName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" - }, - "analyticalStorageTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "conflictResolutionPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" - }, - "defaultTtl": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" - }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" - }, - "kind": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" - }, - "version": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" - }, - "paths": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" - }, - "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", - "uniqueKeyPolicyKeys": { - "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "4781880351108045502" - }, - "name": "DocumentDB Database Account SQL Database Containers", - "description": "This module deploys a SQL Database Container in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "sqlDatabaseName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" - }, - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - }, - "nullable": true - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the SQL Database resource." - }, - "nullable": true - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the container." - }, - "nullable": true - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" - }, - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - }, - "nullable": true - }, - "kind": { - "type": "string", - "defaultValue": "Hash", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "defaultValue": 1, - "allowedValues": [ - 1, - 2 - ], - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - } - }, - "variables": { - "copy": [ - { - "name": "partitionKeyPaths", - "count": "[length(parameters('paths'))]", - "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" - } - ] - }, - "resources": { - "databaseAccount::sqlDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "container": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the container was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "sqlDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlRoleDefinitions": { - "copy": { - "name": "databaseAccount_sqlRoleDefinitions", - "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "dataActions": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" - }, - "roleName": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "sqlRoleAssignments": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "8514367433037227852" - }, - "name": "DocumentDB Database Account SQL Role Definitions.", - "description": "This module deploys a SQL Role Definision in a CosmosDB Account." - }, - "definitions": { - "sqlRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SQL Role Assignments." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." } }, - "name": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, "nullable": true, "metadata": { - "description": "Optional. The unique identifier of the Role Definition." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, - "roleName": { - "type": "string", + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + "description": "Optional. The lock settings of the service." } }, - "dataActions": { + "roleAssignments": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/roleAssignmentType" }, - "minLength": 1, + "nullable": true, "metadata": { - "description": "Required. An array of data actions that are allowed." + "description": "Optional. Array of role assignments to create." } }, - "assignableScopes": { + "diagnosticSettings": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/diagnosticSettingFullType" }, "nullable": true, "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." } }, - "sqlRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleAssignmentType" - }, - "nullable": true, + "projectDescription": { + "type": "string", "metadata": { - "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." + "description": "Optional: Description for the project which needs to be created." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" } } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, "enableReferencedModulesTelemetry": false }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } }, - "sqlRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, { - "dataActions": "[parameters('dataActions')]" + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } } ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" } }, - "databaseAccount_sqlRoleAssignments": { + "cognitiveService_roleAssignments": { "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "roleDefinitionIdOrName": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" - }, "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, "enableTelemetry": { "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -53912,67 +48721,331 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "name": { + "subnetResourceId": { "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "principalId": { + "customNetworkInterfaceName": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "roleDefinitionIdOrName": { + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "ipVersionType": { "type": "string", "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" - }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -53988,444 +49061,290 @@ } } }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "ipVersionType": "[parameters('ipVersionType')]" } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL Role Assignment." + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + "dependsOn": [ + "privateEndpoint" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL Role Assignment." + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "sqlRoleDefinition" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL Role Definition." - }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL Role Definition." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." - }, - "value": "[resourceGroup().name]" - }, - "roleName": { - "type": "string", - "metadata": { - "description": "The role name of the SQL Role Definition." - }, - "value": "[reference('sqlRoleDefinition').roleName]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlRoleAssignments": { - "copy": { - "name": "databaseAccount_sqlRoleAssignments", - "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "roleDefinitionIdOrName": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11817543900771838380" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated SQL Role Definition." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." - } - } - }, - "variables": { - "builtInDataPlaneRoleNames": { - "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", - "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - }, - "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", - "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } - } - } - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[variables('formattedRoleDefinition')]", - "scope": "[variables('formattedScope')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL Role Definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_sqlDatabases", - "databaseAccount_sqlRoleDefinitions" - ] - }, - "databaseAccount_cassandraRoleDefinitions": { - "copy": { - "name": "databaseAccount_cassandraRoleDefinitions", - "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" - }, - "roleName": { - "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" - }, - "dataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" - }, - "notDataActions": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" - }, - "assignableScopes": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" - }, - "cassandraRoleAssignments": { - "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10787709019875067397" - }, - "name": "DocumentDB Database Account Cassandra Role Definitions.", - "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." - }, - "definitions": { - "cassandraRoleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the role assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The unique identifier of the Role Definition." - } - }, - "roleName": { - "type": "string", - "metadata": { - "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." - } - }, - "dataActions": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." - } - }, - "notDataActions": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." - } - }, - "assignableScopes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." - } - }, - "cassandraRoleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/cassandraRoleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraRoleDefinition": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", - "properties": { - "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", - "permissions": [ - { - "dataActions": "[parameters('dataActions')]", - "notDataActions": "[parameters('notDataActions')]" - } - ], - "roleName": "[parameters('roleName')]", - "type": "CustomRole" + } } }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "roleDefinitionId": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" } }, "template": { @@ -54435,605 +49354,369 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" - }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "principalId": { - "type": "string", + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } - }, - "roleDefinitionId": { + } + }, + "parameters": { + "keyVaultName": { "type": "string", "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." + "description": "Required. The name of the Key Vault to set the secrets in." } }, - "scope": { - "type": "string", - "nullable": true, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + "description": "Required. The secrets to set in the Key Vault." } } }, "resources": { - "databaseAccount": { + "keyVault": { "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + "value": "[parameters('secretsToSet')[copyIndex()].value]" } } }, "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." + "description": "The references to the secrets exported to the provided Key Vault." }, - "value": "[resourceGroup().name]" + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } } } } - }, - "dependsOn": [ - "cassandraRoleDefinition" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cassandra role definition." - }, - "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cassandra role definition." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the cassandra role definition was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraRoleAssignments": { - "copy": { - "name": "databaseAccount_cassandraRoleAssignments", - "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "roleDefinitionId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" - }, - "principalId": { - "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" - }, - "scope": { - "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14764024820910071147" - }, - "name": "DocumentDB Database Account Cassandra Role Assignments.", - "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name unique identifier of the Cassandra Role Assignment." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The unique identifier of the associated Cassandra Role Definition." - } - }, - "scope": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraRoleAssignment": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra Role Assignment." - }, - "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra Role Assignment." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra Role Assignment was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount", - "databaseAccount_cassandraKeyspaces", - "databaseAccount_cassandraRoleDefinitions" - ] - }, - "databaseAccount_mongodbDatabases": { - "copy": { - "name": "databaseAccount_mongodbDatabases", - "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "collections": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" - }, - "autoscaleSettings": { - "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "13897098552792121791" - }, - "name": "DocumentDB Database Account MongoDB Databases", - "description": "This module deploys a MongoDB Database within a CosmosDB Account." - }, - "definitions": { - "collectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a collection." - } - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." } }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "items": { - "$ref": "#/definitions/collectionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "autoscaleSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" - }, - "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "mongodbDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "mongodbDatabase_collections": { - "copy": { - "name": "mongodbDatabase_collections", - "count": "[length(coalesce(parameters('collections'), createArray()))]" - }, + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[parameters('projectName')]" }, - "mongodbDatabaseName": { - "value": "[parameters('name')]" + "desc": { + "value": "[parameters('projectDescription')]" }, - "name": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + "aiServicesName": { + "value": "[parameters('name')]" }, - "indexes": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + "location": { + "value": "[parameters('location')]" }, - "shardKey": { - "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + "tags": { + "value": "[parameters('tags')]" }, - "throughput": { - "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "16151461445994734468" - }, - "name": "DocumentDB Database Account MongoDB Database Collections", - "description": "This module deploys a MongoDB Database Collection." + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } }, "parameters": { - "databaseAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + "description": "Required. Name of the AI Services project." } }, - "mongodbDatabaseName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + "description": "Required. The location of the Project resource." } }, - "name": { + "desc": { "type": "string", + "defaultValue": "[parameters('name')]", "metadata": { - "description": "Required. Name of the collection." + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." } }, - "throughput": { - "type": "int", - "defaultValue": 400, + "aiServicesName": { + "type": "string", "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." } }, - "indexes": { - "type": "array", + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" - }, - "description": "Required. Indexes for the collection." + "description": "Optional. Tags to be applied to the resources." } }, - "shardKey": { - "type": "object", + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" - }, - "description": "Required. ShardKey for the collection." + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" } } }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]", - "indexes": "[parameters('indexes')]", - "shardKey": "[parameters('shardKey')]" - } + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" } } - ], + }, "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the mongodb database collection." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the mongodb database collection." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", "metadata": { - "description": "The name of the resource group the mongodb database collection was created in." + "description": "AI Project metadata including name, resource ID, and API endpoint." }, - "value": "[resourceGroup().name]" + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } } } } - }, - "dependsOn": [ - "mongodbDatabase" - ] + } } }, "outputs": { - "name": { - "type": "string", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "The name of the mongodb database." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": "[parameters('name')]" + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the mongodb database." + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the mongodb database was created in." + "description": "The private endpoints of the congitive services account." }, - "value": "[resourceGroup().name]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } } } }, "dependsOn": [ - "databaseAccount" + "cognitiveServiceNew" ] }, - "databaseAccount_gremlinDatabases": { - "copy": { - "name": "databaseAccount_gremlinDatabases", - "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" - }, + "existing_cognitive_service_dependencies": { + "condition": "[variables('useExistingService')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", + "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + "value": "[variables('existingCognitiveServiceDetails')[8]]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[variables('resolvedDeployments')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "lock": { + "value": "[parameters('lock')]" }, - "graphs": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + }, + "roleAssignments": { + "value": "[variables('resolvedRoleAssignments')]" }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" }, - "throughput": { - "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -55043,598 +49726,786 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "11959636451300474346" - }, - "name": "DocumentDB Database Account Gremlin Databases", - "description": "This module deploys a Gremlin Database within a CosmosDB Account." + "version": "0.42.1.51946", + "templateHash": "8883353547455396972" + } }, "definitions": { - "graphType": { + "privateEndpointOutputType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the graph." + "description": "The name of the private endpoint." } }, - "tags": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true + "description": "The resource ID of the private endpoint." + } }, - "indexingPolicy": { - "type": "object", + "groupId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true + "description": "The group Id for the private endpoint Group." + } }, - "partitionKeyPaths": { + "customDnsConfigs": { "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "nullable": true + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a graph." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." + "description": "The type for the private endpoint output." } }, - "tags": { + "deploymentType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin database resource." - }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." - } - }, - "graphs": { - "type": "array", - "items": { - "$ref": "#/definitions/graphType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" - }, - "gremlinDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "gremlinDatabase_gremlinGraphs": { - "copy": { - "name": "gremlinDatabase_gremlinGraphs", - "count": "[length(coalesce(parameters('graphs'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" - }, - "gremlinDatabaseName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "indexingPolicy": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" - }, - "partitionKeyPaths": { - "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "10487122333182352122" - }, - "name": "DocumentDB Database Accounts Gremlin Databases Graphs", - "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." - }, - "parameters": { + "model": { + "type": "object", + "properties": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the graph." + "description": "Required. The name of Cognitive Services account deployment model." } }, - "tags": { - "type": "object", + "format": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" - }, - "description": "Optional. Tags of the Gremlin graph resource." - }, - "nullable": true + "description": "Required. The format of Cognitive Services account deployment model." + } }, - "databaseAccountName": { + "version": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Required. The version of Cognitive Services account deployment model." } - }, - "gremlinDatabaseName": { + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + "description": "Required. The name of the resource model definition representing SKU." } }, - "indexingPolicy": { - "type": "object", + "capacity": { + "type": "int", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" - }, - "description": "Optional. Indexing policy of the graph." - }, - "nullable": true + "description": "Optional. The capacity of the resource model definition representing SKU." + } }, - "partitionKeyPaths": { - "type": "array", + "tier": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" - }, - "description": "Optional. List of paths using which data within the container can be partitioned." - }, - "nullable": true - } - }, - "resources": { - "databaseAccount::gremlinDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" + "description": "Optional. The tier of the resource model definition representing SKU." + } }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } }, - "gremlinGraph": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "indexingPolicy": "[parameters('indexingPolicy')]", - "partitionKey": { - "paths": "[parameters('partitionKeyPaths')]" - } - } + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." } } }, - "outputs": { - "name": { + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "The name of the graph." - }, - "value": "[parameters('name')]" + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceId": { + "memberName": { "type": "string", "metadata": { - "description": "The resource ID of the graph." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "resourceGroupName": { + "privateIPAddress": { "type": "string", "metadata": { - "description": "The name of the resource group the graph was created in." - }, - "value": "[resourceGroup().name]" + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." } } }, - "dependsOn": [ - "gremlinDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Gremlin database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Gremlin database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Gremlin database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_tables": { - "copy": { - "name": "databaseAccount_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "maxThroughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "1787500858429182824" - }, - "name": "Azure Cosmos DB account tables", - "description": "This module deploys a table within an Azure Cosmos DB Account." - }, - "parameters": { - "name": { - "type": "string", "metadata": { - "description": "Required. Name of the table." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "tags": { + "_1.privateEndpointPrivateDnsZoneGroupType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } }, - "description": "Optional. Tags for the table." + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } }, - "nullable": true - }, - "databaseAccountName": { - "type": "string", "metadata": { - "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "throughput": { - "type": "int", - "nullable": true, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-04-15", - "name": "[parameters('databaseAccountName')]" }, - "table": { - "type": "Microsoft.DocumentDB/databaseAccounts/tables", - "apiVersion": "2025-04-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "diagnosticSettingFullType": { + "type": "object", "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_cassandraKeyspaces": { - "copy": { - "name": "databaseAccount_cassandraKeyspaces", - "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "tables": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" - }, - "views": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "throughput": { - "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15257396763463366586" + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } }, - "name": "DocumentDB Database Account Cassandra Keyspaces", - "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." - }, - "definitions": { - "tableType": { + "privateEndpointSingleServiceType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the table." + "description": "Optional. The name of the Private Endpoint." } }, - "schema": { - "type": "object", + "location": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" - }, - "description": "Required. Schema definition for the table." + "description": "Optional. The location to deploy the Private Endpoint to." } }, - "tags": { - "type": "object", + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags for the table." + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } }, - "defaultTtl": { - "type": "int", + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + "description": "Optional. Specify the type of lock." } }, - "analyticalStorageTtl": { - "type": "int", + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, "nullable": true, "metadata": { - "description": "Optional. Analytical TTL for the table." + "description": "Optional. Array of role assignments to create." } }, - "throughput": { - "type": "int", + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "enableTelemetry": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra table." + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "viewType": { + "roleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the view." + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." } }, - "viewDefinition": { + "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. View definition (CQL statement)." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "tags": { - "type": "object", + "principalId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" - }, - "description": "Optional. Tags for the view." - }, - "nullable": true + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } }, - "throughput": { - "type": "int", + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], "nullable": true, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + "description": "Optional. The principal type of the assigned principal ID." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", + "description": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." } } }, "metadata": { - "__bicep_export!": true, - "description": "The type of a Cassandra view (materialized view)." + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } } }, @@ -55642,90 +50513,267 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the Cassandra keyspace." + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." } }, "tags": { "type": "object", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra keyspace resource." + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } }, - "databaseAccountName": { - "type": "string", + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." } }, - "tables": { + "privateEndpoints": { "type": "array", "items": { - "$ref": "#/definitions/tableType" + "$ref": "#/definitions/privateEndpointSingleServiceType" }, - "defaultValue": [], + "nullable": true, "metadata": { - "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, - "views": { + "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/viewType" + "$ref": "#/definitions/roleAssignmentType" }, - "defaultValue": [], + "nullable": true, "metadata": { - "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + "description": "Optional. Array of role assignments to create." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "defaultValue": 4000, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + "description": "Optional. The diagnostic settings of the service." } }, - "throughput": { - "type": "int", - "nullable": true, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, "resources": { - "databaseAccount": { + "cognitiveService": { "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]" }, - "cassandraKeyspace": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" - } + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" }, - "dependsOn": [ - "databaseAccount" - ] + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } }, - "cassandraKeyspace_tables": { + "cognitiveService_privateEndpoints": { "copy": { - "name": "cassandraKeyspace_tables", - "count": "[length(parameters('tables'))]" + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -55733,31 +50781,42 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('tables')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { - "value": "[parameters('name')]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "schema": { - "value": "[parameters('tables')[copyIndex()].schema]" + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" }, - "analyticalStorageTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, - "throughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, - "defaultTtl": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" }, "tags": { - "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -55767,795 +50826,761 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15998065591386988132" + "version": "0.41.2.15936", + "templateHash": "18436885663402767850" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } }, - "name": "DocumentDB Database Account Cassandra Keyspaces Tables", - "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } }, "parameters": { "name": { "type": "string", "metadata": { - "description": "Required. Name of the Cassandra table." + "description": "Required. Name of the private endpoint resource to create." } }, - "tags": { - "type": "object", + "subnetResourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" - }, - "description": "Optional. Tags of the Cassandra table resource." - }, - "nullable": true + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } }, - "databaseAccountName": { - "type": "string", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "cassandraKeyspaceName": { + "customNetworkInterfaceName": { "type": "string", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "schema": { - "type": "object", + "ipConfigurations": { + "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations" }, - "description": "Required. Schema definition for the Cassandra table." - } + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, + "ipVersionType": { + "type": "string", "metadata": { - "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType" + }, + "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4." + }, + "defaultValue": "IPv4" }, - "throughput": { - "type": "int", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "nullable": true, "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + "description": "Optional. Location for all Resources." } }, - "defaultTtl": { - "type": "int", - "defaultValue": 0, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { - "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + "description": "Optional. The lock settings of the service." } - } - }, - "resources": { - "databaseAccount::cassandraKeyspace": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "cassandraTable": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "schema": "[parameters('schema')]", - "defaultTtl": "[parameters('defaultTtl')]", - "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra table was created in." + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "cassandraKeyspace" - ] - }, - "cassandraKeyspace_views": { - "copy": { - "name": "cassandraKeyspace_views", - "count": "[length(parameters('views'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('views')[copyIndex()].name]" - }, - "cassandraKeyspaceName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "viewDefinition": { - "value": "[parameters('views')[copyIndex()].viewDefinition]" - }, - "throughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "6617803098467821091" - }, - "name": "DocumentDB Database Account Cassandra Keyspaces Views", - "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." - }, - "parameters": { - "name": { - "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the Cassandra view." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags" }, - "description": "Optional. Tags of the Cassandra view resource." + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." }, "nullable": true }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "cassandraKeyspaceName": { - "type": "string", + "customDnsConfigs": { + "type": "array", "metadata": { - "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true }, - "viewDefinition": { - "type": "string", + "manualPrivateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true }, - "throughput": { - "type": "int", - "nullable": true, + "privateLinkServiceConnections": { + "type": "array", "metadata": { - "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + "description": "Optional. Enable/Disable usage telemetry for module." } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { - "databaseAccount::cassandraKeyspace": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2025-05-01-preview", - "name": "[parameters('databaseAccountName')]" + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "cassandraView": { - "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", - "apiVersion": "2025-05-01-preview", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "resource": { - "id": "[parameters('name')]", - "viewDefinition": "[parameters('viewDefinition')]" + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + "ipVersionType": "[parameters('ipVersionType')]" + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, "dependsOn": [ - "databaseAccount" + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9935179114830442414" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2025-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" ] } }, "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the Cassandra view." + "description": "The name of the private endpoint." }, "value": "[parameters('name')]" }, - "resourceId": { + "location": { "type": "string", "metadata": { - "description": "The resource ID of the Cassandra view." + "description": "The location the resource was deployed into." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]" }, - "resourceGroupName": { + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { "type": "string", + "nullable": true, "metadata": { - "description": "The name of the resource group the Cassandra view was created in." + "description": "The group Id for the private endpoint Group." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } - }, - "dependsOn": [ - "cassandraKeyspace" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Cassandra keyspace." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Cassandra keyspace." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Cassandra keyspace was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_privateEndpoints": { - "copy": { - "name": "databaseAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." - }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-12-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-12-01').key2)), createArray()))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "13560950051680758953" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2026-02-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2026-02-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } } } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" } } }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -56563,13 +51588,22 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + "value": "[parameters('projectName')]" }, - "privateEndpointName": { + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" } }, "template": { @@ -56579,313 +51613,252 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "version": "0.42.1.51946", + "templateHash": "2020223351407601593" + } }, "definitions": { - "privateDnsZoneGroupConfigType": { + "aiProjectOutputType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Required. Name of the AI project." } }, - "privateDnsZoneResourceId": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." } } }, "metadata": { "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." + "description": "Output type representing AI project information." } } }, "parameters": { - "privateEndpointName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. Name of the AI Services project." } }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Required. The location of the Project resource." } }, - "name": { + "desc": { "type": "string", - "defaultValue": "default", + "defaultValue": "[parameters('name')]", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" } } }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, "resources": { - "privateEndpoint": { + "cogServiceReference": { "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('aiServicesName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" } } }, "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "AI Project metadata including name, resource ID, and API endpoint." }, - "value": "[resourceGroup().name]" + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } } } } - }, - "dependsOn": [ - "privateEndpoint" - ] + } } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "networkInterfaceResourceIds": { + "privateEndpoints": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/privateEndpointOutputType" }, "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." + "description": "The private endpoints of the congitive services account." }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } } } - }, - "dependsOn": [ - "databaseAccount" - ] + } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the database account." + "description": "The name of the cognitive services account." }, - "value": "[parameters('name')]" + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the database account." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the database account was created in." + "description": "The resource ID of the cognitive services account." }, - "value": "[resourceGroup().name]" + "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" }, - "systemAssignedMIPrincipalId": { + "subscriptionId": { "type": "string", - "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "The resource group the cognitive services account was deployed into." }, - "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" }, - "location": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The resource group the cognitive services account was deployed into." }, - "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" }, "endpoint": { "type": "string", "metadata": { - "description": "The endpoint of the database account." - }, - "value": "[reference('databaseAccount').documentEndpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the database account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "primaryReadWriteKey": { - "type": "securestring", - "metadata": { - "description": "The primary read-write key." + "description": "The service endpoint of the cognitive services account." }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoint)]" }, - "primaryReadOnlyKey": { - "type": "securestring", + "endpoints": { + "$ref": "#/definitions/endpointType", "metadata": { - "description": "The primary read-only key." + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." }, - "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).properties.endpoints)]" }, - "primaryReadWriteConnectionString": { - "type": "securestring", + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "description": "The primary read-write connection string." + "description": "The principal ID of the system assigned identity." }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')), 'identity'), 'principalId'))]" }, - "primaryReadOnlyConnectionString": { - "type": "securestring", + "location": { + "type": "string", "metadata": { - "description": "The primary read-only connection string." + "description": "The location the resource was deployed into." }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-12-01', 'full'), reference('cognitiveServiceNew', '2025-12-01', 'full')).location)]" }, - "secondaryReadWriteKey": { - "type": "securestring", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "The secondary read-write key." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" }, - "secondaryReadOnlyKey": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only key." + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, - "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" - }, - "secondaryReadWriteConnectionString": { - "type": "securestring", "metadata": { - "description": "The secondary read-write connection string." + "description": "The private endpoints of the congitive services account." }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" }, - "secondaryReadOnlyConnectionString": { - "type": "securestring", - "metadata": { - "description": "The secondary read-only connection string." - }, - "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" } } } }, "dependsOn": [ - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cosmosDB)]", - "virtualNetwork" + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmAiSearch": { + { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", @@ -58020,136 +52993,796 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "authOptions": "[parameters('authOptions')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]", + "computeType": "[parameters('computeType')]", + "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" + } + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } } - } - } - } - }, - "searchService": { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "[parameters('sku')]" - }, - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "authOptions": "[parameters('authOptions')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryptionWithCmk": { - "enforcement": "[parameters('cmkEnforcement')]" - }, - "hostingMode": "[parameters('hostingMode')]", - "networkRuleSet": "[parameters('networkRuleSet')]", - "partitionCount": "[parameters('partitionCount')]", - "replicaCount": "[parameters('replicaCount')]", - "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", - "semanticSearch": "[parameters('semanticSearch')]", - "computeType": "[parameters('computeType')]", - "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" - } - }, - "searchService_diagnosticSettings": { - "copy": { - "name": "searchService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] } }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "searchService" - ] - }, - "searchService_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "searchService" - ] - }, - "searchService_roleAssignments": { - "copy": { - "name": "searchService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } }, "dependsOn": [ "searchService" ] }, - "searchService_privateEndpoints": { + "searchService_sharedPrivateLinkResources": { "copy": { - "name": "searchService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 }, "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -58157,42 +53790,22 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "searchServiceName": { + "value": "[parameters('name')]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" } }, "template": { @@ -58202,3165 +53815,8016 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "16604612898799598358" + "version": "0.39.26.7824", + "templateHash": "2115224445601868607" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource." }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, + "parameters": { + "searchServiceName": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type of a private dns zone group." + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." } }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + "name": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." } }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, + "privateLinkResourceId": { + "type": "string", "metadata": { - "description": "The type of a private DNS zone group configuration.", - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } + "description": "Required. The resource ID of the resource the shared private link resource is for." } }, - "roleAssignmentType": { - "type": "object", + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2025-05-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2025-05-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "696453183181258843" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "The resourceId of the exported secret." } }, - "condition": { + "secretUri": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + "description": "The secret URI of the exported secret." } - }, - "conditionVersion": { + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Required. The name of the secret to set." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "value": { + "type": "securestring", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Required. The value of the secret to set." } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { + "keyVaultName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Required. The name of the Key Vault to set the ecrets in." } }, - "applicationSecurityGroupResourceIds": { + "secretsToSet": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/secretToSetType" }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Required. The secrets to set in the Key Vault." } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" }, - "ipConfigurations": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" - }, - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" }, - "nullable": true - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" } - }, - "roleAssignments": { + } + }, + "outputs": { + "secretsSet": { "type": "array", "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "$ref": "#/definitions/secretSetType" }, - "nullable": true - }, - "customDnsConfigs": { - "type": "array", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" - }, - "description": "Optional. Custom DNS configurations." + "description": "The references to the secrets exported to the provided Key Vault." }, - "nullable": true - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" - }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2025-05-01', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[reference('searchService').endpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryKey": { + "type": "securestring", + "metadata": { + "description": "The primary admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" + }, + "secondaryKey": { + "type": "securestring", + "metadata": { + "description": "The secondaryKey admin API key of the search service." + }, + "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the AI Search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "Name of the AI Search service." + }, + "value": "[parameters('name')]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint URL of the AI Search service." + }, + "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "System-assigned identity principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('st{0}', replace(variables('solutionSuffix'), '-', ''))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "minimumTlsVersion": { + "value": "TLS1_2" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Queue Data Contributor", + "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]", + "principalType": "ServicePrincipal" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "[if(parameters('enablePrivateNetworking'), 'Deny', 'Allow')]", + "ipRules": [] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "supportsHttpsTrafficOnly": { + "value": true + }, + "accessTier": { + "value": "Hot" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-blob-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-blob-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-blob', 'privateDnsZoneResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageBlob), 64)), '2025-04-01').outputs.resourceId.value))), 'subnetResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value, 'service', 'blob'), createObject('name', format('pep-queue-{0}', variables('solutionSuffix')), 'customNetworkInterfaceName', format('nic-queue-{0}', variables('solutionSuffix')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'storage-dns-zone-group-queue', 'privateDnsZoneResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageQueue), 64)), '2025-04-01').outputs.resourceId.value))), 'subnetResourceId', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value, 'service', 'queue'))), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "14745424667769468789" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name of the storage account." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Azure region for the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "managedIdentities": { + "type": "object", + "metadata": { + "description": "Managed identity configuration." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "metadata": { + "description": "Minimum TLS version." + } + }, + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Role assignments for the storage account." + } + }, + "networkAcls": { + "type": "object", + "metadata": { + "description": "Network ACL configuration." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether infrastructure encryption is required." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Whether HTTPS traffic only is enforced." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "metadata": { + "description": "Access tier for the storage account." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether blob public access is allowed." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Public network access setting." + } + }, + "privateEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Private endpoint configuration." + } + } + }, + "resources": { + "storageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.storage.storage-account.{0}', parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "minimumTlsVersion": { + "value": "[parameters('minimumTlsVersion')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "networkAcls": { + "value": "[parameters('networkAcls')]" + }, + "requireInfrastructureEncryption": { + "value": "[parameters('requireInfrastructureEncryption')]" + }, + "supportsHttpsTrafficOnly": { + "value": "[parameters('supportsHttpsTrafficOnly')]" + }, + "accessTier": { + "value": "[parameters('accessTier')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": "[parameters('allowBlobPublicAccess')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1254456195180100771" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } }, - "nullable": true - }, - "privateLinkServiceConnections": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + "ipAddresses": { + "type": "array", + "items": { + "type": "string" }, - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoints output." + } + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.38.5.1644", - "templateHash": "24141742673128945" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a private DNS zone group configuration." - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-10-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-10-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" - } - } - } - ] - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." } - }, - "dependsOn": [ - "privateEndpoint" - ] + } } }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network configuration." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey1 secret name to create." + } + }, + "connectionString1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString1 secret name to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey2 secret name to create." + } + }, + "connectionString2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString2 secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the exported secrets." + } + }, + "localUserType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a local user." + } + }, + "blobServiceType": { + "type": "object", + "properties": { + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/blobCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "versionDeletePolicyDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of days to keep a version before deleting. If set, a lifecycle management policy will be created to handle deleting previous versions." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a blob service." + } + }, + "fileServiceType": { + "type": "object", + "properties": { + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "description": "Optional. Protocol settings for file service." + }, + "nullable": true + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" }, - "name": { + "description": "Optional. The service properties for soft delete." + }, + "nullable": true + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/fileCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a file service." + } + }, + "queueServiceType": { + "type": "object", + "properties": { + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/queueCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a queue service." + } + }, + "tableServiceType": { + "type": "object", + "properties": { + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/tableCorsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a table service." + } + }, + "objectReplicationPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the object replication policy. If not provided, a GUID will be generated." + } + }, + "destinationStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the destination storage account." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. The storage account object replication rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy." + } + }, + "_1.immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/container/main.bicep" + } + } + }, + "_2.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "location": { + "memberName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", - "output": true - }, - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } }, - "groupId": { + "privateIPAddress": { "type": "string", - "nullable": true, "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." } } }, - "dependsOn": [ - "searchService" - ] + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "searchService_sharedPrivateLinkResources": { - "copy": { - "name": "searchService_sharedPrivateLinkResources", - "count": "[length(parameters('sharedPrivateLinkResources'))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "_2.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" - }, - "searchServiceName": { - "value": "[parameters('name')]" + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } }, - "privateLinkResourceId": { - "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_2.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "blobCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" }, - "groupId": { - "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" }, - "requestMessage": { - "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" }, - "resourceRegion": { - "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/_1.immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "metadata": { + "type": "object", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "2115224445601868607" - }, - "name": "Search Services Private Link Resources", - "description": "This module deploys a Search Service Private Link Resource." - }, - "parameters": { - "searchServiceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." - } - }, - "privateLinkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the resource the shared private link resource is for." - } - }, - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The group ID from the provider of resource the shared private link resource is for." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Required. The request message for requesting approval of the shared private link resource." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" }, - "resourceRegion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." - } - } + "description": "Optional. A name-value pair to associate with the container as metadata." }, - "resources": { - "searchService": { - "existing": true, - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", - "name": "[parameters('searchServiceName')]" - }, - "sharedPrivateLinkResource": { - "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", - "apiVersion": "2025-05-01", - "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", - "properties": { - "privateLinkResourceId": "[parameters('privateLinkResourceId')]", - "groupId": "[parameters('groupId')]", - "requestMessage": "[parameters('requestMessage')]", - "resourceRegion": "[parameters('resourceRegion')]" - } - } + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the shared private link resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the shared private link resource." - }, - "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the shared private link resource was created in." - }, - "value": "[resourceGroup().name]" - } + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." } } }, - "dependsOn": [ - "searchService" - ] + "metadata": { + "description": "The type of a storage container.", + "__bicep_imported_from!": { + "sourceTemplate": "blob-service/main.bicep" + } + } }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "customerManagedKeyWithAutoRotateType": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + "keyVersion": { + "type": "string", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "696453183181258843" - } - }, - "definitions": { - "secretSetType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." } }, - "metadata": { - "__bicep_export!": true - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-11-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2024-11-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, - "dependsOn": [ - "searchService" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the search service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the search service." - }, - "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the search service was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "fileCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } }, - "value": "[reference('searchService', '2025-05-01', 'full').location]" - }, - "endpoint": { - "type": "string", "metadata": { - "description": "The endpoint of the search service." - }, - "value": "[reference('searchService').endpoint]" + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep", + "originalIdentifier": "corsRuleType" + } + } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } }, "metadata": { - "description": "The private endpoints of the search service." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + "description": "The type for a file share.", + "__bicep_imported_from!": { + "sourceTemplate": "file-service/main.bicep" } } }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "primaryKey": { - "type": "securestring", "metadata": { - "description": "The primary admin API key of the search service." - }, - "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "secondaryKey": { - "type": "securestring", - "metadata": { - "description": "The secondaryKey admin API key of the search service." - }, - "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" - } - } - } - }, - "dependsOn": [ - "searchService" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the AI Search service." - }, - "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "Name of the AI Search service." - }, - "value": "[parameters('name')]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "Endpoint URL of the AI Search service." - }, - "value": "[format('https://{0}.search.windows.net', parameters('name'))]" - }, - "identityPrincipalId": { - "type": "string", - "metadata": { - "description": "System-assigned identity principal ID." - }, - "value": "[coalesce(tryGet(tryGet(reference('searchServiceUpdate').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" - } - } - } - } - }, - "avmAppConfig": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "tags": { - "value": { - "app": "[variables('solutionSuffix')]", - "location": "[parameters('location')]" - } - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "sku": { - "value": "Standard" - }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", - "disableLocalAuth": { - "value": false - }, - "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_API').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Web').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[tryGet(tryGet(reference('avmContainerApp_Workflow').outputs, 'systemAssignedMIPrincipalId'), 'value')]", - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalType": "ServicePrincipal" - } - ] - }, - "keyValues": { - "value": [ - { - "name": "APP_AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_AZURE_OPENAI_MODEL", - "value": "[parameters('gptModelName')]" - }, - { - "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "APP_COSMOS_CONTAINER_PROCESS", - "value": "Processes" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMA", - "value": "Schemas" - }, - { - "name": "APP_COSMOS_DATABASE", - "value": "ContentProcess" - }, - { - "name": "APP_CPS_CONFIGURATION", - "value": "cps-configuration" - }, - { - "name": "APP_CPS_MAX_FILESIZE_MB", - "value": "20" - }, - { - "name": "APP_CPS_PROCESSES", - "value": "cps-processes" - }, - { - "name": "APP_MESSAGE_QUEUE_EXTRACT", - "value": "content-pipeline-extract-queue" - }, - { - "name": "APP_MESSAGE_QUEUE_INTERVAL", - "value": "5" - }, - { - "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", - "value": "180" - }, - { - "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", - "value": "10" - }, - { - "name": "APP_PROCESS_STEPS", - "value": "extract,map,evaluate,save" - }, - { - "name": "APP_STORAGE_BLOB_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.blob]" - }, - { - "name": "APP_STORAGE_QUEUE_URL", - "value": "[reference('avmStorageAccount').outputs.serviceEndpoints.value.queue]" - }, - { - "name": "APP_AI_PROJECT_ENDPOINT", - "value": "[coalesce(tryGet(reference('avmAiServices').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" - }, - { - "name": "APP_COSMOS_CONNSTR", - "value": "[listOutputsWithSecureValues('avmCosmosDB', '2025-04-01').primaryReadWriteConnectionString]" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", - "value": "claimprocesses" - }, - { - "name": "APP_COSMOS_CONTAINER_BATCHES", - "value": "batches" - }, - { - "name": "APP_COSMOS_CONTAINER_SCHEMASET", - "value": "Schemasets" - }, - { - "name": "APP_CPS_PROCESS_BATCH", - "value": "process-batch" - }, - { - "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", - "value": "[format('http://{0}/', reference('avmContainerApp_API').outputs.name.value)]" - }, - { - "name": "APP_CPS_POLL_INTERVAL_SECONDS", - "value": "3" - }, - { - "name": "APP_STORAGE_ACCOUNT_NAME", - "value": "[reference('avmStorageAccount').outputs.name.value]" - }, - { - "name": "CLAIM_PROCESS_QUEUE_NAME", - "value": "claim-process-queue" - }, - { - "name": "DEAD_LETTER_QUEUE_NAME", - "value": "claim-process-dead-letter-queue" - }, - { - "name": "AZURE_OPENAI_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", - "value": "[parameters('gptModelName')]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "AZURE_OPENAI_ENDPOINT_BASE", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", - "value": "" - }, - { - "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", - "value": "" - }, - { - "name": "AZURE_TRACING_ENABLED", - "value": "True" - }, - { - "name": "GLOBAL_LLM_SERVICE", - "value": "AzureOpenAI" - }, - { - "name": "GPT5_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "GPT5_CHAT_DEPLOYMENT_NAME", - "value": "gpt-5" - }, - { - "name": "GPT5_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - }, - { - "name": "PHI4_API_VERSION", - "value": "2024-05-01-preview" - }, - { - "name": "PHI4_CHAT_DEPLOYMENT_NAME", - "value": "phi-4" - }, - { - "name": "PHI4_ENDPOINT", - "value": "[reference('avmAiServices').outputs.endpoint.value]" - } - ] - }, - "publicNetworkAccess": { - "value": "Enabled" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } - }, - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "object-replication-policy/policy/main.bicep" } } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } } }, - "memberName": { - "type": "string", + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_2.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } } }, - "privateIPAddress": { - "type": "string", + "queueCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep", + "originalIdentifier": "corsRuleType" + } } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a queue.", + "__bicep_imported_from!": { + "sourceTemplate": "queue-service/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_2.secretSetOutputType", "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "description": "An exported secret's references." } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + }, + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "tableCorsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "description": "The type for a cors rule.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep", + "originalIdentifier": "corsRuleType" } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure App Configuration." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], - "metadata": { - "description": "Optional. Pricing tier of App Configuration." - } - }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], - "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "keyValues": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." - } - }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. All Replicas to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, - "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "description": "The type for a table.", + "__bicep_imported_from!": { + "sourceTemplate": "table-service/main.bicep" + } + } } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "extendedLocationZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Extended Zone location (ex 'losangeles'). When supplied, the storage account will be created in the specified zone under the parent location. The extended zone must be available in the supplied parent location." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS", + "Standard_GRS", + "Standard_GZRS", + "Standard_RAGRS", + "Standard_RAGZRS", + "StandardV2_LRS", + "StandardV2_ZRS", + "StandardV2_GRS", + "StandardV2_GZRS", + "Premium_LRS", + "Premium_ZRS", + "PremiumV2_LRS", + "PremiumV2_ZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name - note: certain V2 SKUs require the use of: kind = FileStorage." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "Cold" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if set to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/azureFilesIdentityBasedAuthentication" + }, + "description": "Optional. Provides the identity based authentication settings for Azure Files." + }, + "nullable": true + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Optional. The Storage Account ManagementPolicies Rules." + }, + "nullable": true }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." - }, - "parameters": { - "name": { - "type": "string", + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, "metadata": { - "description": "Required. Name of the key." + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." } }, - "value": { + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The value of the key-value." + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." } }, - "appConfigurationName": { + "dnsEndpointType": { "type": "string", + "nullable": true, + "allowedValues": [ + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "$ref": "#/definitions/blobServiceType", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "description": "Optional. Blob service and containers to deploy." } }, - "contentType": { + "fileServices": { + "$ref": "#/definitions/fileServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "$ref": "#/definitions/queueServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "$ref": "#/definitions/tableServiceType", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_2", + "TLS1_3" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/localUserType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "description": "Optional. The lock settings of the service." } }, "tags": { "type": "object", - "nullable": true, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/tags" + }, "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "sasExpirationAction": { + "type": "string", + "defaultValue": "Log", + "allowedValues": [ + "Block", + "Log" + ], + "metadata": { + "description": "Optional. The SAS expiration action. Allowed values are Block and Log." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "immutableStorageWithVersioning": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts@2025-01-01#properties/properties/properties/immutableStorageWithVersioning" + }, + "description": "Optional. The property is immutable and can only be set to true at the account creation time. When set to true, it enables object level immutability for all the new containers in the account by default. Cannot be enabled for ADLS Gen2 storage accounts." + }, + "nullable": true + }, + "objectReplicationPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Object replication policies for the storage account." } } }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "immutabilityValidation": "[if(and(equals(parameters('enableHierarchicalNamespace'), true()), not(empty(parameters('immutableStorageWithVersioning')))), fail('Configuration error: Immutable storage with versioning cannot be enabled when hierarchical namespace is enabled.'), null())]", + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "formattedManagementPolicies": "[union(coalesce(parameters('managementPolicyRules'), createArray()), if(and(and(not(empty(parameters('blobServices'))), coalesce(tryGet(parameters('blobServices'), 'isVersioningEnabled'), false())), not(equals(tryGet(parameters('blobServices'), 'versionDeletePolicyDays'), null()))), createArray(createObject('name', 'DeletePreviousVersions (auto-created)', 'enabled', true(), 'type', 'Lifecycle', 'definition', createObject('actions', createObject('version', createObject('delete', createObject('daysAfterCreationGreaterThan', parameters('blobServices').versionDeletePolicyDays))), 'filters', createObject('blobTypes', createArray('blockBlob', 'appendBlob'))))), createArray()))]", + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" + }, "resources": { - "appConfiguration": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", "existing": true, - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.32.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[and(not(variables('isHSMManagedCMK')), not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2025-05-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('allowSharedKeyAccess', parameters('allowSharedKeyAccess'), 'defaultToOAuthAuthentication', parameters('defaultToOAuthAuthentication'), 'allowCrossTenantReplication', parameters('allowCrossTenantReplication'), 'allowedCopyScope', parameters('allowedCopyScope'), 'customDomain', createObject('name', parameters('customDomainName'), 'useSubDomainName', parameters('customDomainUseSubDomainName')), 'dnsEndpointType', parameters('dnsEndpointType'), 'isLocalUserEnabled', parameters('isLocalUserEnabled'), 'encryption', union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires either specifying the ''keyVersion'' or omitting the ''autoRotationEnabled'' property. Setting ''autoRotationEnabled'' to false without a ''keyVersion'' is not allowed.'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject())), 'accessTier', if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null()), 'sasPolicy', if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', parameters('sasExpirationAction'), 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null()), 'supportsHttpsTrafficOnly', parameters('supportsHttpsTrafficOnly'), 'isSftpEnabled', parameters('enableSftp'), 'isNfsV3Enabled', if(parameters('enableNfsV3'), parameters('enableNfsV3'), ''), 'largeFileSharesState', if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null()), 'minimumTlsVersion', parameters('minimumTlsVersion'), 'networkAcls', if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny')), 'allowBlobPublicAccess', parameters('allowBlobPublicAccess'), 'publicNetworkAccess', if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))), if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), createObject('azureFilesIdentityBasedAuthentication', parameters('azureFilesIdentityBasedAuthentication')), createObject()), if(not(equals(parameters('enableHierarchicalNamespace'), null())), createObject('isHnsEnabled', parameters('enableHierarchicalNamespace')), createObject()), createObject('immutableStorageWithVersioning', parameters('immutableStorageWithVersioning'))))]", + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sa-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(variables('formattedManagementPolicies'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key values." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[variables('formattedManagementPolicies')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "4000605059554016072" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" + }, + "description": "Required. The Storage Account ManagementPolicies Rules." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-mgmtpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[parameters('name')]" + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key values." + "storageAccount_localUsers": { + "copy": { + "name": "storageAccount_localUsers", + "count": "[length(coalesce(parameters('localUsers'), createArray()))]" }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the batch account was deployed into." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "1801226901235196767" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-localuser.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" - }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", - "metadata": { - "description": "Optional. Name of the replica." - } - }, - "appConfigurationName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." - } + "dependsOn": [ + "storageAccount" + ] }, - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - } - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration was deployed into." + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "468225492069709453" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "nullable": true + }, + "publicAccess": { + "type": "string", + "allowedValues": [ + "Blob", + "Container", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a storage container." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "description": "The type for an immutability policy.", + "__bicep_imported_from!": { + "sourceTemplate": "container/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs. Cannot be enabled for ADLS Gen2 storage accounts." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false, + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[parameters('defaultServiceVersion')]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(and(not(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'Storage')), empty(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'extendedLocation'))), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicy')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "273904034769611992" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "immutabilityPolicyType": { + "type": "object", + "properties": { + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an immutability policy." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Storage Container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicy": { + "$ref": "#/definitions/immutabilityPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/blobServices/containers@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair to associate with the container as metadata." + }, + "defaultValue": {} + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[parameters('defaultEncryptionScope')]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(parameters('immutableStorageWithVersioningEnabled'), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "container_immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicy'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ImmutPol', deployment().name), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicy'), 'allowProtectedAppendWritesAll')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "15304742179563677019" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-containerimmutpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "blobServices" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "storageAccount" + ] }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the replica that was deployed." + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + }, + "corsRules": { + "value": "[tryGet(parameters('fileServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "17583198711200998285" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "fileShareType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share." + } + }, + "accessTier": { + "type": "string", + "allowedValues": [ + "Cool", + "Hot", + "Premium", + "TransactionOptimized" + ], + "nullable": true, + "metadata": { + "description": "Optional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "enabledProtocols": { + "type": "string", + "allowedValues": [ + "NFS", + "SMB" + ], + "nullable": true, + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "shareQuota": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a file share." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/protocolSettings" + }, + "description": "Optional. Protocol settings for file service." + }, + "defaultValue": {} + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/fileServices@2024-01-01#properties/properties/properties/shareDeleteRetentionPolicy" + }, + "description": "Optional. The service properties for soft delete." + }, + "defaultValue": { + "enabled": true, + "days": 7 + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "items": { + "$ref": "#/definitions/fileShareType" + }, + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-FileShare-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "provisionedBandwidthMibps": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + }, + "provisionedIops": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10353179772982843397" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]", + "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", + "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[parameters('name')]" + "dependsOn": [ + "storageAccount" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the replica that was deployed." + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + }, + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "9644461291744477521" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "queueType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the queue." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. Metadata to set on the queue." + }, + "nullable": true + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a queue." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "items": { + "$ref": "#/definitions/queueType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "12812824360066955039" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01#properties/properties/properties/metadata" + }, + "description": "Optional. A name-value pair that represents queue metadata." + }, + "defaultValue": {} + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-queue.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue service." + }, + "value": "[resourceGroup().name]" + } + } + } }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "dependsOn": [ + "storageAccount" + ] }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" + }, + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + }, + "corsRules": { + "value": "[tryGet(parameters('tableServices'), 'corsRules')]" } }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "10320403358700650147" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default", + "enableReferencedModulesTelemetry": false + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "11362260974696477885" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-table.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-06-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2025-06-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } } } }, - "metadata": { - "__bicep_export!": true - } + "dependsOn": [ + "storageAccount" + ] }, - "ipConfigurationType": { - "type": "object", + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" } }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "13227497656004178962" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } } - }, - "memberName": { + } + }, + "parameters": { + "keyVaultName": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + "description": "Required. The name of the Key Vault to set the ecrets in." } }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { + "secretsToSet": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/secretToSetType" }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." + "description": "Required. The secrets to set in the Key Vault." } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "name": "[parameters('keyVaultName')]" }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2024-11-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" } } }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } } } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" }, "dependsOn": [ - "privateEndpoint" + "storageAccount" ] }, - "privateEndpoint_roleAssignments": { + "storageAccount_objectReplicationPolicies": { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "name": "storageAccount_objectReplicationPolicies", + "count": "[length(coalesce(parameters('objectReplicationPolicies'), createArray()))]" }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2025-04-01", + "name": "[format('{0}-Storage-ObjRepPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { + "storageAccountName": { "value": "[parameters('name')]" }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + "destinationAccountResourceId": { + "value": "[coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()].destinationStorageAccountResourceId]" + }, + "enableMetrics": { + "value": "[coalesce(tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'enableMetrics'), false())]" + }, + "rules": { + "value": "[tryGet(coalesce(parameters('objectReplicationPolicies'), createArray())[copyIndex()], 'rules')]" } }, "template": { @@ -61370,1480 +61834,1004 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "version": "0.41.2.15936", + "templateHash": "1894366578172550759" }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." }, "definitions": { - "privateDnsZoneGroupConfigType": { + "objectReplicationPolicyRuleType": { "type": "object", "properties": { - "name": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." } } }, "metadata": { - "__bicep_export!": true + "description": "The type of an object replication policy rule.", + "__bicep_imported_from!": { + "sourceTemplate": "policy/main.bicep" + } } } }, "parameters": { - "privateEndpointName": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Optional. Name of the policy." } }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, + "storageAccountName": { + "type": "string", + "maxLength": 24, "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + "description": "Required. The name of the parent Storage Account." } }, - "name": { + "destinationAccountResourceId": { "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." } } }, "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] + "destAccountResourceIdParts": "[split(parameters('destinationAccountResourceId'), '/')]", + "destAccountName": "[if(not(empty(variables('destAccountResourceIdParts'))), last(variables('destAccountResourceIdParts')), parameters('destinationAccountResourceId'))]", + "destAccountSubscription": "[if(greater(length(variables('destAccountResourceIdParts')), 2), variables('destAccountResourceIdParts')[2], subscription().subscriptionId)]", + "destAccountResourceGroupName": "[if(greater(length(variables('destAccountResourceIdParts')), 4), variables('destAccountResourceIdParts')[4], resourceGroup().name)]" }, "resources": { - "privateEndpoint": { + "storageAccount": { "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "destinationPolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-dest-{1}', deployment().name, variables('destAccountName')), 64)]", + "subscriptionId": "[variables('destAccountSubscription')]", + "resourceGroup": "[variables('destAccountResourceGroupName')]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('name'), 'default')]" + }, + "storageAccountName": { + "value": "[variables('destAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "value": "[parameters('rules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } + } + } } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the app configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the app configuration." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration store was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the app configuration." - }, - "value": "[reference('configurationStore').endpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the app configuration." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "avmAiServices", - "avmContainerApp", - "avmContainerApp_API", - "avmContainerApp_Web", - "avmContainerApp_Workflow", - "avmCosmosDB", - "avmStorageAccount", - "logAnalyticsWorkspace" - ] - }, - "avmAppConfig_update": { - "condition": "[parameters('enablePrivateNetworking')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.configuration-store.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('appcs-{0}', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enablePurgeProtection": { - "value": "[parameters('enablePurgeProtection')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "publicNetworkAccess": { - "value": "Disabled" - }, - "privateEndpoints": { - "value": [ - { - "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", - "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", - "privateDnsZoneGroup": { - "privateDnsZoneGroupConfigs": [ - { - "name": "appconfig-dns-zone-group", - "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)).outputs.resourceId.value]" - } - ] - }, - "subnetResourceId": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "396653159019145335" - }, - "name": "App Configuration Stores", - "description": "This module deploys an App Configuration Store." - }, - "definitions": { - "dataPlaneProxyType": { - "type": "object", - "properties": { - "authenticationMode": { - "type": "string", - "allowedValues": [ - "Local", - "Pass-through" - ], - "nullable": true, - "metadata": { - "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." - } - }, - "privateLinkDelegation": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data plane proxy." - } - }, - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." + "sourcePolicy": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('{0}-ObjRep-Policy-source-{1}', deployment().name, parameters('storageAccountName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[reference('destinationPolicy').outputs.policyId.value]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "sourceStorageAccountResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + }, + "destinationAccountResourceId": { + "value": "[parameters('destinationAccountResourceId')]" + }, + "enableMetrics": { + "value": "[parameters('enableMetrics')]" + }, + "rules": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('rules'))]", + "input": "[union(parameters('rules')[copyIndex('value')], createObject('ruleId', reference('destinationPolicy').outputs.rules.value[copyIndex('value')].ruleId))]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.41.2.15936", + "templateHash": "14995722372031126283" + }, + "name": "Storage Account Object Replication Policy", + "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." + }, + "definitions": { + "objectReplicationPolicyRuleType": { + "type": "object", + "properties": { + "ruleId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID of the rule. Auto-generated on destination account. Required for source account." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Required. The name of the source container." + } + }, + "destinationContainerName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the destination container. If not provided, the same name as the source container will be used." + } + }, + "filters": { + "type": "object", + "properties": { + "prefixMatch": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The prefix to match for the replication policy rule." + } + }, + "minCreationTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The minimum creation time to match for the replication policy rule." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The filters for the object replication policy rule." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of an object replication policy rule." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the policy." + } + }, + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. The name of the Storage Account on which to create the policy." + } + }, + "sourceStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the source storage account for replication." + } + }, + "destinationAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the destination storage account for replication." + } + }, + "enableMetrics": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether metrics are enabled for the object replication policy." + } + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/objectReplicationPolicyRuleType" + }, + "metadata": { + "description": "Required. Rules for the object replication policy." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2025-01-01", + "name": "[parameters('storageAccountName')]" + }, + "objectReplicationPolicy": { + "type": "Microsoft.Storage/storageAccounts/objectReplicationPolicies", + "apiVersion": "2025-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "rules", + "count": "[length(parameters('rules'))]", + "input": { + "ruleId": "[tryGet(parameters('rules')[copyIndex('rules')], 'ruleId')]", + "sourceContainer": "[parameters('rules')[copyIndex('rules')].containerName]", + "destinationContainer": "[coalesce(tryGet(parameters('rules')[copyIndex('rules')], 'destinationContainerName'), parameters('rules')[copyIndex('rules')].containerName)]", + "filters": "[if(not(equals(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), null())), createObject('prefixMatch', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'prefixMatch'), 'minCreationTime', tryGet(tryGet(parameters('rules')[copyIndex('rules')], 'filters'), 'minCreationTime')), null())]" + } + } + ], + "destinationAccount": "[parameters('destinationAccountResourceId')]", + "metrics": { + "enabled": "[coalesce(parameters('enableMetrics'), false())]" + }, + "sourceAccount": "[parameters('sourceStorageAccountResourceId')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/objectReplicationPolicies', parameters('storageAccountName'), parameters('name'))]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').policyId]" + }, + "rules": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Storage/storageAccounts/objectReplicationPolicies@2025-01-01#properties/properties/properties/rules", + "output": true + }, + "description": "Rules created Object Replication Policy." + }, + "value": "[reference('objectReplicationPolicy').rules]" + } + } + } + }, + "dependsOn": [ + "destinationPolicy" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group name of the provisioned resources." + }, + "value": "[resourceGroup().name]" + }, + "objectReplicationPolicyId": { + "type": "string", + "metadata": { + "description": "Resource ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.objectReplicationPolicyId.value]" + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Policy ID of the created Object Replication Policy in the source account." + }, + "value": "[reference('sourcePolicy').outputs.policyId.value]" + } + } } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] } }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "replicaLocationType": { - "type": "object", - "properties": { - "replicaLocation": { - "type": "string", - "metadata": { - "description": "Required. Location of the replica." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the replica." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a replica location" - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" }, - "memberName": { + "name": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" }, - "privateIPAddress": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS Zone Group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - } - }, - "metadata": { - "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "_1.roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "customerManagedKeyWithAutoRotateType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." - } - }, - "autoRotationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } + "description": "The resource group of the deployed storage account." }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2025-06-01', 'full').location]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." + }, + "value": "[reference('storageAccount').primaryEndpoints]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Storage Account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "primaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The primary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" + }, + "secondaryAccessKey": { + "type": "securestring", + "metadata": { + "description": "The secondary access key of the storage account." + }, + "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" + }, + "primaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" + }, + "secondaryConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary connection string of the storage account." + }, + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, + } + }, + "outputs": { + "resourceId": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } + "description": "Resource ID of the storage account." }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } + "value": "[reference('storageAccount').outputs.resourceId.value]" }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/_1.lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" - }, - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, + "name": { + "type": "string", "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } + "description": "Name of the storage account." + }, + "value": "[reference('storageAccount').outputs.name.value]" }, - "roleAssignmentType": { + "serviceEndpoints": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } + "description": "Service endpoints exposed by the storage account." + }, + "value": "[reference('storageAccount').outputs.serviceEndpoints.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageBlob), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').storageQueue), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.cosmos-db-mongo.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "name": { + "value": "[format('cosmos-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "databaseName": { + "value": "default" + }, + "collections": { + "value": [] + }, + "serverVersion": { + "value": "7.0" + }, + "consistencyLevel": { + "value": "Session" + }, + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "enableAutomaticFailover": { + "value": "[parameters('enableRedundancy')]" + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "enablePrivateNetworking": { + "value": "[parameters('enablePrivateNetworking')]" + }, + "privateEndpointSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value), createObject('value', ''))]", + "privateDnsZoneResourceIds": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cosmosDB), 64)), '2025-04-01').outputs.resourceId.value)), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "7370292565038719427" } }, "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix used to derive the resource name." + } + }, "name": { "type": "string", + "defaultValue": "[format('cosmos-{0}', parameters('solutionName'))]", "metadata": { - "description": "Required. Name of the Azure App Configuration." + "description": "Name of the Cosmos DB account." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Azure region for the resource." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Tags to apply to the resource." } }, - "sku": { + "databaseName": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Developer", - "Standard", - "Premium" - ], + "defaultValue": "default", "metadata": { - "description": "Optional. Pricing tier of App Configuration." + "description": "MongoDB database name." } }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], + "collections": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." + "description": "MongoDB collections to create." } }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, + "serverVersion": { + "type": "string", + "defaultValue": "7.0", + "allowedValues": [ + "4.2", + "5.0", + "6.0", + "7.0" + ], "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." + "description": "MongoDB server version." } }, - "enablePurgeProtection": { + "enableAnalyticalStorage": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + "description": "Enable analytical storage (Synapse Link)." } }, - "publicNetworkAccess": { + "consistencyLevel": { "type": "string", - "nullable": true, + "defaultValue": "Session", "allowedValues": [ - "Enabled", - "Disabled" + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 7, - "metadata": { - "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + "description": "Default consistency level." } }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", - "nullable": true, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The customer managed key definition." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "keyValues": { + "diagnosticSettings": { "type": "array", - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + "description": "Diagnostic settings for monitoring." } }, - "replicaLocations": { - "type": "array", - "items": { - "$ref": "#/definitions/replicaLocationType" - }, - "nullable": true, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. All Replicas to create." + "description": "Public network access setting." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, + "enablePrivateNetworking": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Whether to enable private networking." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "privateEndpointSubnetId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Subnet resource ID for the private endpoint." } }, - "roleAssignments": { + "privateDnsZoneResourceIds": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Private DNS zone resource IDs for Cosmos DB (MongoDB)." } }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "dataPlaneProxy": { - "$ref": "#/definitions/dataPlaneProxyType", - "nullable": true, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + "description": "Enable zone redundancy." } }, - "enableTelemetry": { + "enableAutomaticFailover": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Enable automatic failover." } }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, + "haLocation": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Optional. HA paired region for multi-region failover when redundancy is enabled." } } }, "variables": { "copy": [ { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneResourceIds'))]", + "input": { + "name": "[format('dns-zone-{0}', copyIndex('privateDnsZoneConfigs'))]", + "privateDnsZoneResourceId": "[parameters('privateDnsZoneResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", - "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + ] }, "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2024-11-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "cosmosAccount": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2024-12-01-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "configurationStore": { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[variables('identity')]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", - "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "configurationStore_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_diagnosticSettings": { - "copy": { - "name": "configurationStore_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_roleAssignments": { - "copy": { - "name": "configurationStore_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_keyValues": { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(coalesce(parameters('keyValues'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[take(format('avm.res.document-db.database-account.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "appConfigurationName": { + "name": { "value": "[parameters('name')]" }, - "name": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + "location": { + "value": "[parameters('location')]" }, - "value": { - "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + "tags": { + "value": "[parameters('tags')]" }, - "contentType": { - "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } + "capabilitiesToAdd": { + "value": [ + "EnableMongo" + ] + }, + "serverVersion": { + "value": "[parameters('serverVersion')]" + }, + "enableAnalyticalStorage": { + "value": "[parameters('enableAnalyticalStorage')]" + }, + "defaultConsistencyLevel": { + "value": "[parameters('consistencyLevel')]" + }, + "mongodbDatabases": { + "value": [ + { + "name": "[parameters('databaseName')]", + "collections": "[parameters('collections')]" + } + ] + }, + "diagnosticSettings": "[if(not(empty(parameters('diagnosticSettings'))), createObject('value', parameters('diagnosticSettings')), createObject('value', createArray()))]", + "networkRestrictions": { + "value": { + "networkAclBypass": "None", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + } + }, + "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-{0}', parameters('name')), 'customNetworkInterfaceName', format('nic-{0}', parameters('name')), 'subnetResourceId', parameters('privateEndpointSubnetId'), 'service', 'MongoDB', 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', variables('privateDnsZoneConfigs'))))), createObject('value', createArray()))]", + "zoneRedundant": { + "value": "[parameters('zoneRedundant')]" + }, + "enableAutomaticFailover": { + "value": "[parameters('enableAutomaticFailover')]" + }, + "failoverLocations": "[if(and(parameters('zoneRedundant'), not(empty(parameters('haLocation')))), createObject('value', createArray(createObject('failoverPriority', 0, 'isZoneRedundant', true(), 'locationName', parameters('location')), createObject('failoverPriority', 1, 'isZoneRedundant', true(), 'locationName', parameters('haLocation')))), createObject('value', createArray(createObject('locationName', parameters('location'), 'failoverPriority', 0, 'isZoneRedundant', false()))))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -62852,390 +62840,1280 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4166303424618131775" + "version": "0.40.2.10011", + "templateHash": "1772014800591596213" }, - "name": "App Configuration Stores Key Values", - "description": "This module deploys an App Configuration Store Key Value." + "name": "Azure Cosmos DB account", + "description": "This module deploys an Azure Cosmos DB account. The API used for the account is determined by the child resources that are deployed." }, - "parameters": { - "name": { - "type": "string", + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group ID for the private endpoint group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "fully-qualified domain name (FQDN) that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses for the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "failoverLocationType": { + "type": "object", + "properties": { + "failoverPriority": { + "type": "int", + "metadata": { + "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." + } + }, + "isZoneRedundant": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag to indicate whether or not this region is an AvailabilityZone region. Defaults to true." + } + }, + "locationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the region." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the failover location." + } + }, + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for NoSQL native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL native role-based access control assignment." + } + }, + "sqlRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. This must be unique within the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully-qualified scopes at or below which role-based access control assignments may be created using this definition. This setting allows application of this definition on the entire account or any underlying resource. This setting must have at least one element. Scopes higher than the account level are not enforceable as assignable scopes. Resources referenced in assignable scopes do not need to exist at creation. Defaults to the current account scope." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/nestedSqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for NoSQL or Table native role-based access control definition." + } + }, + "networkRestrictionType": { + "type": "object", + "properties": { + "ipRules": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A single IPv4 address or a single IPv4 address range in Classless Inter-Domain Routing (CIDR) format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: `10.0.0.0/8`, `100.64.0.0/10`, `172.16.0.0/12`, `192.168.0.0/16`, since these are not enforceable by the IP address filter. Example of valid inputs: `23.40.210.245` or `23.40.210.0/8`." + } + }, + "networkAclBypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the network ACL bypass for Azure services. Default to \"None\"." + } + }, + "publicNetworkAccess": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Whether requests from the public network are allowed. Default to \"Disabled\"." + } + }, + "virtualNetworkRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of a subnet." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of virtual network access control list (ACL) rules configured for the account." + } + }, + "networkAclBypassResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the network restriction." + } + }, + "gremlinDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a gremlin databae." + } + }, + "mongoDbType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a mongo databae." + } + }, + "sqlDatabaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a sql database." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "maxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a table." + } + }, + "cassandraStandaloneRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the Azure Cosmos DB for Apache Cassandra native role-based access control definition." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated Microsoft Entra ID principal to which access is being granted through this role-based access control assignment. The tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this role-based access control assignment. Defaults to the current account." + } + } + }, "metadata": { - "description": "Required. Name of the key." + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control assignment." } }, - "value": { - "type": "string", + "cassandraRoleDefinitionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role-based access control definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the role-based access control definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings are currently undocumented (API version 2025-05-01-preview). Expected to follow format similar to SQL RBAC once documented by Microsoft." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra supports deny rules for granular access control. Valid data action strings are currently undocumented (API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition." + } + }, + "assignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of role-based access control assignments to be created for the definition." + } + } + }, "metadata": { - "description": "Required. The value of the key-value." + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB for Apache Cassandra native role-based access control definition." } }, - "appConfigurationName": { - "type": "string", + "cassandraKeyspaceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraTableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraViewType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `autoscaleSettingsMaxThroughput`. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level and not at the keyspace level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + } + }, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "__bicep_export!": true, + "description": "The type for an Azure Cosmos DB Cassandra keyspace." } }, - "contentType": { - "type": "string", - "nullable": true, + "defaultIdentityType": { + "type": "object", + "discriminator": { + "propertyName": "name", + "mapping": { + "FirstPartyIdentity": { + "$ref": "#/definitions/defaultIdentityFirstPartyType" + }, + "SystemAssignedIdentity": { + "$ref": "#/definitions/defaultIdentitySystemAssignedType" + }, + "UserAssignedIdentity": { + "$ref": "#/definitions/defaultIdentityUserAssignedType" + } + } + }, "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "__bicep_export!": true, + "description": "The type for the default identity." } }, - "tags": { + "defaultIdentityFirstPartyType": { "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "FirstPartyIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } } - } - }, - "resources": { - "appConfiguration": { - "existing": true, - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2025-02-01-preview", - "name": "[parameters('appConfigurationName')]" }, - "keyValues": { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "defaultIdentitySystemAssignedType": { + "type": "object", "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" + "name": { + "type": "string", + "allowedValues": [ + "SystemAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + } } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key values." - }, - "value": "[parameters('name')]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key values." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + "defaultIdentityUserAssignedType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "UserAssignedIdentity" + ], + "metadata": { + "description": "Required. The type of default identity to use." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the user assigned identity to use as the default identity." + } + } + } }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the batch account was deployed into." + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_replicas": { - "copy": { - "name": "configurationStore_replicas", - "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appConfigurationName": { - "value": "[parameters('name')]" - }, - "replicaLocation": { - "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "12609356088985615301" - }, - "name": "App Configuration Replicas", - "description": "This module deploys an App Configuration Replica." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", "metadata": { - "description": "Optional. Name of the replica." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "appConfigurationName": { - "type": "string", + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "replicaLocation": { - "type": "string", + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, "metadata": { - "description": "Required. Location of the replica." + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } - } - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/replicas", - "apiVersion": "2025-02-01-preview", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", - "location": "[parameters('replicaLocation')]" - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration was deployed into." - }, - "value": "[resourceGroup().name]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the replica that was deployed." + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } }, - "value": "[parameters('name')]" + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-role-definition/main.bicep" + } + } }, - "resourceId": { - "type": "string", + "cassandraTableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, "metadata": { - "description": "The resource ID of the replica that was deployed." + "description": "The type of a Cassandra table.", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "tableType" + } + } + }, + "cassandraViewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - }, - "configurationStore_privateEndpoints": { - "copy": { - "name": "configurationStore_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "metadata": { + "description": "The type of a Cassandra view (materialized view).", + "__bicep_imported_from!": { + "sourceTemplate": "cassandra-keyspace/main.bicep", + "originalIdentifier": "viewType" + } + } }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { + "collectionType": { "type": "object", "properties": { "name": { "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." } }, - "privateDnsZoneGroupConfigs": { + "indexes": { "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." } } }, "metadata": { - "__bicep_export!": true + "description": "The type of a collection.", + "__bicep_imported_from!": { + "sourceTemplate": "mongodb-database/main.bicep" + } } }, - "ipConfigurationType": { + "containerType": { "type": "object", "properties": { "name": { "type": "string", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Required. Name of the container." } }, - "properties": { + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" }, + "minLength": 1, + "maxLength": 3, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." } } }, "metadata": { - "__bicep_export!": true + "description": "The type of a container.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-database/main.bicep" + } + } + }, + "customerManagedKeyAndVaultOnlyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if only the key vault & key may be specified.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "privateLinkServiceConnectionType": { + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. The name of the diagnostic setting." } }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. Properties of private link service connection." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } }, "metadata": { - "__bicep_export!": true + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } } }, - "customDnsConfigType": { + "graphType": { "type": "object", "properties": { - "fqdn": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." + "description": "Required. Name of the graph." } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true } }, "metadata": { - "__bicep_export!": true + "description": "The type of a graph.", + "__bicep_imported_from!": { + "sourceTemplate": "gremlin-database/main.bicep" + } } }, "lockType": { @@ -63259,35 +64137,223 @@ "metadata": { "description": "Optional. Specify the type of lock." } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } } }, "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, - "privateDnsZoneGroupConfigType": { + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" + } + } + }, + "nestedSqlRoleAssignmentType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group config." + "description": "Optional. Name unique identifier of the SQL Role Assignment." } }, - "privateDnsZoneResourceId": { + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "description": "The type for the SQL Role Assignments.", + "__bicep_imported_from!": { + "sourceTemplate": "sql-role-definition/main.bicep", + "originalIdentifier": "sqlRoleAssignmentType" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Required. The resource id of the private DNS zone." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } }, @@ -63362,7 +64428,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.7.0" } } } @@ -63371,54 +64437,212 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. The name of the account." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Defaults to the current resource group scope location. Location for all resources." } }, - "applicationSecurityGroupResourceIds": { + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the resource." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "databaseAccountOfferType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], + "metadata": { + "description": "Optional. The offer type for the account. Defaults to \"Standard\"." + } + }, + "failoverLocations": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/failoverLocationType" }, "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. The set of locations enabled for the account. Defaults to the location where the account is deployed." } }, - "customNetworkInterfaceName": { + "zoneRedundant": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the single-region account is zone redundant. Defaults to true. This property is ignored for multi-region accounts." + } + }, + "defaultConsistencyLevel": { + "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], + "metadata": { + "description": "Optional. The default consistency level of the account. Defaults to \"Session\"." + } + }, + "disableLocalAuthentication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure that only Microsoft Entra can be used exclusively for authentication. Defaults to true." + } + }, + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether to enable storage analytics. Defaults to false." + } + }, + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions. Defaults to true." + } + }, + "enableFreeTier": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to indicate whether \"Free Tier\" is enabled. Defaults to false." + } + }, + "enableMultipleWriteLocations": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the account to write in multiple locations. Periodic backup must be used if enabled. Defaults to false." + } + }, + "disableKeyBasedMetadataWriteAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable write operations on metadata resources (databases, containers, throughput) via account keys. Defaults to true." + } + }, + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. The maximum stale requests. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000. Defaults to 100000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. The maximum lag time in minutes. Required for \"BoundedStaleness\" consistency level. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400. Defaults to 300." + } + }, + "serverVersion": { "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2", + "5.0", + "6.0", + "7.0" + ], + "metadata": { + "description": "Optional. Specifies the MongoDB server version to use if using Azure Cosmos DB for MongoDB RU. Defaults to \"4.2\"." + } + }, + "sqlDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlDatabaseType" + }, "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Configuration for databases when using Azure Cosmos DB for NoSQL." } }, - "ipConfigurations": { + "mongodbDatabases": { "type": "array", "items": { - "$ref": "#/definitions/ipConfigurationType" + "$ref": "#/definitions/mongoDbType" }, "nullable": true, "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. Configuration for databases when using Azure Cosmos DB for MongoDB RU." } }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", + "gremlinDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/gremlinDatabaseType" + }, "nullable": true, "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Apache Gremlin." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Configuration for databases when using Azure Cosmos DB for Table." + } + }, + "cassandraKeyspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraKeyspaceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration for keyspaces when using Azure Cosmos DB for Apache Cassandra." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "totalThroughputLimit": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The total throughput limit imposed on this account in request units per second (RU/s). Default to unlimited throughput." } }, "lock": { @@ -63435,51 +64659,226 @@ }, "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. An array of control plane Azure role-based access control assignments." } }, - "tags": { - "type": "object", + "sqlRoleDefinitions": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleDefinitionType" + }, "nullable": true, "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control definitions. Allows the creations of custom role definitions." } }, - "customDnsConfigs": { + "sqlRoleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/customDnsConfigType" + "$ref": "#/definitions/sqlRoleAssignmentType" }, "nullable": true, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Optional. Configurations for Azure Cosmos DB for NoSQL native role-based access control assignments." } }, - "manualPrivateLinkServiceConnections": { + "cassandraRoleDefinitions": { "type": "array", "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "$ref": "#/definitions/cassandraRoleDefinitionType" }, "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + "description": "Optional. Configurations for Azure Cosmos DB for Apache Cassandra native role-based access control definitions. Allows the creations of custom role definitions." } }, - "privateLinkServiceConnections": { + "cassandraRoleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" + "$ref": "#/definitions/cassandraStandaloneRoleAssignmentType" }, "nullable": true, "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + "description": "Optional. Azure Cosmos DB for Apache Cassandra native data plane role-based access control assignments. Each assignment references a role definition unique identifier and a principal identifier." } }, - "enableTelemetry": { + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings for the service." + } + }, + "capabilitiesToAdd": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless", + "EnableNoSQLVectorSearch", + "EnableNoSQLFullTextSearch", + "EnableMaterializedViews", + "DeleteAllItemsByPartitionKey" + ], + "metadata": { + "description": "Optional. A list of Azure Cosmos DB specific capabilities for the account." + } + }, + "backupPolicyType": { + "type": "string", + "defaultValue": "Continuous", + "allowedValues": [ + "Periodic", + "Continuous" + ], + "metadata": { + "description": "Optional. Configures the backup mode. Periodic backup must be used if multiple write locations are used. Defaults to \"Continuous\"." + } + }, + "backupPolicyContinuousTier": { + "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], + "metadata": { + "description": "Optional. Configuration values to specify the retention period for continuous mode backup. Default to \"Continuous30Days\"." + } + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. This setting only applies to the periodic backup type. Defaults to 240." + } + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, + "metadata": { + "description": "Optional. An integer representing the time (in hours) that each backup is retained. This setting only applies to the periodic backup type. Defaults to 8." + } + }, + "backupStorageRedundancy": { + "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], + "metadata": { + "description": "Optional. Setting that indicates the type of backup residency. This setting only applies to the periodic backup type. Defaults to \"Local\"." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is advised to use private endpoints whenever possible." + } + }, + "networkRestrictions": { + "$ref": "#/definitions/networkRestrictionType", + "defaultValue": { + "ipRules": [], + "virtualNetworkRules": [], + "publicNetworkAccess": "Disabled" + }, + "metadata": { + "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "Tls12", + "allowedValues": [ + "Tls12" + ], + "metadata": { + "description": "Optional. Setting that indicates the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later. Defaults to \"Tls12\" (TLS 1.2)." + } + }, + "enableBurstCapacity": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Flag to indicate enabling/disabling of Burst Capacity feature on the account. Cannot be enabled for serverless accounts." + } + }, + "enableCassandraConnector": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables the cassandra connector on the Cosmos DB C* account." + } + }, + "enablePartitionMerge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'Partition Merge' feature on the account." + } + }, + "enablePerRegionPerPartitionAutoscale": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag to enable/disable the 'PerRegionPerPartitionAutoscale' feature on the account." + } + }, + "analyticalStorageConfiguration": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/analyticalStorageConfiguration" + }, + "description": "Optional. Analytical storage specific properties." + }, + "nullable": true + }, + "cors": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts@2025-04-15#properties/properties/properties/cors" + }, + "description": "Optional. The CORS policy for the Cosmos DB database account." + }, + "nullable": true + }, + "defaultIdentity": { + "$ref": "#/definitions/defaultIdentityType", + "defaultValue": { + "name": "FirstPartyIdentity" + }, + "metadata": { + "description": "Optional. The default identity for accessing key vault used in features like customer managed keys. Use `FirstPartyIdentity` to use the tenant-level CosmosDB enterprise application. The default identity needs to be explicitly set by the users." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyAndVaultOnlyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition. If specified, the parameter `defaultIdentity` must be configured as well." } } }, @@ -63488,1466 +64887,4187 @@ { "name": "formattedRoleAssignments", "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInControlPlaneRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], - "builtInRoleNames": { + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInControlPlaneRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]" }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "apiVersion": "2024-07-01", + "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.19.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, "mode": "Incremental", - "parameters": { - "name": { - "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - }, - "privateDnsZoneConfigs": { - "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" - } - }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group." - }, - "definitions": { - "privateDnsZoneGroupConfigType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group config." - } - }, - "privateDnsZoneResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the private DNS zone." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDnsZoneConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - }, - "value": "[reference('privateEndpoint').customDnsConfigs]" + "cMKKeyVault": { + "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[2]]", + "resourceGroup": "[split(parameters('customerManagedKey').keyVaultResourceId, '/')[4]]", + "name": "[last(split(parameters('customerManagedKey').keyVaultResourceId, '/'))]" }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the network interfaces associated with the private endpoint." - }, - "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + "databaseAccount": { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB')]", + "properties": "[shallowMerge(createArray(createObject('enableBurstCapacity', if(not(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableServerless')), parameters('enableBurstCapacity'), false()), 'databaseAccountOfferType', parameters('databaseAccountOfferType'), 'analyticalStorageConfiguration', parameters('analyticalStorageConfiguration'), 'defaultIdentity', if(and(not(empty(parameters('defaultIdentity'))), not(equals(tryGet(parameters('defaultIdentity'), 'name'), 'UserAssignedIdentity'))), parameters('defaultIdentity').name, format('UserAssignedIdentity={0}', tryGet(parameters('defaultIdentity'), 'resourceId'))), 'keyVaultKeyUri', if(not(empty(parameters('customerManagedKey'))), if(not(variables('isHSMManagedCMK')), format('{0}', reference('cMKKeyVault::cMKKey').keyUri), format('https://{0}.managedhsm.azure.net/keys/{1}', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')), parameters('customerManagedKey').keyName)), null()), 'enablePartitionMerge', parameters('enablePartitionMerge'), 'enablePerRegionPerPartitionAutoscale', parameters('enablePerRegionPerPartitionAutoscale'), 'backupPolicy', shallowMerge(createArray(createObject('type', parameters('backupPolicyType')), if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject()), if(equals(parameters('backupPolicyType'), 'Periodic'), createObject('periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))), createObject()))), 'capabilities', map(coalesce(parameters('capabilitiesToAdd'), createArray()), lambda('capability', createObject('name', lambdaVariables('capability'))))), if(not(empty(parameters('cors'))), createObject('cors', parameters('cors')), createObject()), if(contains(coalesce(parameters('capabilitiesToAdd'), createArray()), 'EnableCassandra'), createObject('connectorOffer', if(parameters('enableCassandraConnector'), 'Small', null()), 'enableCassandraConnector', parameters('enableCassandraConnector')), createObject()), createObject('minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit')), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'locations', if(not(empty(parameters('failoverLocations'))), map(parameters('failoverLocations'), lambda('failoverLocation', createObject('failoverPriority', lambdaVariables('failoverLocation').failoverPriority, 'locationName', lambdaVariables('failoverLocation').locationName, 'isZoneRedundant', coalesce(tryGet(lambdaVariables('failoverLocation'), 'isZoneRedundant'), true())))), createArray(createObject('failoverPriority', 0, 'locationName', parameters('location'), 'isZoneRedundant', parameters('zoneRedundant'))))), if(or(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), not(empty(parameters('cassandraKeyspaces')))), createObject('consistencyPolicy', shallowMerge(createArray(createObject('defaultConsistencyLevel', parameters('defaultConsistencyLevel')), if(equals(parameters('defaultConsistencyLevel'), 'BoundedStaleness'), createObject('maxStalenessPrefix', parameters('maxStalenessPrefix'), 'maxIntervalInSeconds', parameters('maxIntervalInSeconds')), createObject()))), 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'ipRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()), lambda('ipRule', createObject('ipAddressOrRange', lambdaVariables('ipRule')))), 'virtualNetworkRules', map(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()), lambda('rule', createObject('id', lambdaVariables('rule').subnetResourceId, 'ignoreMissingVNetServiceEndpoint', false()))), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'networkAclBypassResourceIds', tryGet(parameters('networkRestrictions'), 'networkAclBypassResourceIds'), 'isVirtualNetworkFilterEnabled', or(not(empty(tryGet(parameters('networkRestrictions'), 'ipRules'))), not(empty(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('enableAutomaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(or(not(empty(parameters('mongodbDatabases'))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('cassandraKeyspaces')))), createObject('disableLocalAuth', false(), 'disableKeyBasedMetadataWriteAccess', false()), createObject('disableLocalAuth', parameters('disableLocalAuthentication'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess'))), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject())))]", + "dependsOn": [ + "cMKKeyVault::cMKKey" + ] }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." + "databaseAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" }, - "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" - } - } - } - }, - "dependsOn": [ - "configurationStore" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the app configuration." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the app configuration." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app configuration store was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the app configuration." - }, - "value": "[reference('configurationStore').endpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the app configuration." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "avmAppConfig", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').appConfig)]", - "virtualNetwork" - ] - }, - "avmContainerApp_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-app', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessor" - } - ] - } - ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": "[if(parameters('enableScalability'), createArray(createObject('name', 'http-scaler', 'http', createObject('metadata', createObject('concurrentRequests', 100)))), createArray())]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_diagnosticSettings": { + "copy": { + "name": "databaseAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_roleAssignments": { + "copy": { + "name": "databaseAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlDatabases": { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(coalesce(parameters('sqlDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('sqlDatabases'), createArray())[copyIndex()].name]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'containers')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('sqlDatabases'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "3972888645334640168" + }, + "name": "DocumentDB Database Account SQL Databases", + "description": "This module deploys a SQL Database in a CosmosDB Account." + }, + "definitions": { + "containerType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "allowedValues": [ + 1, + 2 + ], + "nullable": true, + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a container." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL database resource." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "container": { + "copy": { + "name": "container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('containers'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'analyticalStorageTtl')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "conflictResolutionPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'conflictResolutionPolicy')]" + }, + "defaultTtl": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultTtl')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "kind": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'kind')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'version')]" + }, + "paths": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'paths')]" + }, + "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'throughput')))]", + "uniqueKeyPolicyKeys": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'uniqueKeyPolicyKeys')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "4781880351108045502" + }, + "name": "DocumentDB Database Account SQL Database Containers", + "description": "This module deploys a SQL Database Container in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." + } + }, + "conflictResolutionPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/conflictResolutionPolicy" + }, + "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "minValue": -1, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "maxValue": 1000000, + "metadata": { + "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the SQL Database resource." + }, + "nullable": true + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3, + "metadata": { + "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the container." + }, + "nullable": true + }, + "uniqueKeyPolicyKeys": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2025-04-15#properties/properties/properties/resource/properties/uniqueKeyPolicy/properties/uniqueKeys" + }, + "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." + }, + "nullable": true + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash" + ], + "metadata": { + "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." + } + }, + "version": { + "type": "int", + "defaultValue": 1, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." + } + } + }, + "variables": { + "copy": [ + { + "name": "partitionKeyPaths", + "count": "[length(parameters('paths'))]", + "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" + } + ] + }, + "resources": { + "databaseAccount::sqlDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "container": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": "[shallowMerge(createArray(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'id', parameters('name'), 'indexingPolicy', parameters('indexingPolicy'), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()), if(not(equals(parameters('defaultTtl'), null())), createObject('defaultTtl', parameters('defaultTtl')), createObject())))]", + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlRoleDefinitions": { + "copy": { + "name": "databaseAccount_sqlRoleDefinitions", + "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "dataActions": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].dataActions]" + }, + "roleName": { + "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "sqlRoleAssignments": { + "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "8514367433037227852" + }, + "name": "DocumentDB Database Account SQL Role Definitions.", + "description": "This module deploys a SQL Role Definision in a CosmosDB Account." + }, + "definitions": { + "sqlRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the SQL Role Assignments." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of data actions that are allowed." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Collection. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "sqlRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/sqlRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of SQL Role Assignments to be created for the SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "enableReferencedModulesTelemetry": false + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionIdOrName": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "sqlRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The role name of the SQL Role Definition." + }, + "value": "[reference('sqlRoleDefinition').roleName]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "databaseAccount_sqlRoleAssignments": { + "copy": { + "name": "databaseAccount_sqlRoleAssignments", + "count": "[length(coalesce(parameters('sqlRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-sqlra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionIdOrName": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('sqlRoleAssignments'), createArray())[copyIndex()], 'scope')]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11817543900771838380" + }, + "name": "DocumentDB Database Account SQL Role Assignments.", + "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the SQL Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated SQL Role Definition." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource id for which access is being granted through this Role Assignment. Defaults to the root of the database account, but can also be scoped to e.g., the container and database level." + } + } + }, + "variables": { + "builtInDataPlaneRoleNames": { + "Cosmos DB Built-in Data Reader": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]", + "Cosmos DB Built-in Data Contributor": "[format('{0}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + }, + "formattedRoleDefinition": "[coalesce(tryGet(variables('builtInDataPlaneRoleNames'), parameters('roleDefinitionIdOrName')), if(contains(parameters('roleDefinitionIdOrName'), '/sqlRoleDefinitions/'), parameters('roleDefinitionIdOrName'), format('{0}/sqlRoleDefinitions/{1}', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('roleDefinitionIdOrName'))))]", + "formattedScope": "[replace(replace(coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))), '/sqlDatabases/', '/dbs/'), '/containers/', '/colls/')]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.doctdb-dbacct-sqlroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "sqlRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[variables('formattedRoleDefinition')]", + "scope": "[variables('formattedScope')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(variables('formattedRoleDefinition'), parameters('principalId'), variables('formattedScope'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL Role Definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_sqlDatabases", + "databaseAccount_sqlRoleDefinitions" + ] + }, + "databaseAccount_cassandraRoleDefinitions": { + "copy": { + "name": "databaseAccount_cassandraRoleDefinitions", + "count": "[length(coalesce(parameters('cassandraRoleDefinitions'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-rd-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'name')]" + }, + "roleName": { + "value": "[coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()].roleName]" + }, + "dataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" + }, + "notDataActions": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'notDataActions')]" + }, + "assignableScopes": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignableScopes')]" + }, + "cassandraRoleAssignments": { + "value": "[tryGet(coalesce(parameters('cassandraRoleDefinitions'), createArray())[copyIndex()], 'assignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10787709019875067397" + }, + "name": "DocumentDB Database Account Cassandra Role Definitions.", + "description": "This module deploys a Cassandra Role Definition in a CosmosDB Account." + }, + "definitions": { + "cassandraRoleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the role assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted. Defaults to the current account." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The unique identifier of the Role Definition." + } + }, + "roleName": { + "type": "string", + "metadata": { + "description": "Required. A user-friendly name for the Role Definition. Must be unique for the database account." + } + }, + "dataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are allowed. Note: Valid data action strings for Cassandra API are currently undocumented (as of API version 2025-05-01-preview). Please refer to official Azure documentation once available." + } + }, + "notDataActions": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. An array of data actions that are denied. Note: Unlike SQL RBAC, Cassandra RBAC supports deny rules (notDataActions) for granular access control. Valid data action strings are currently undocumented (as of API version 2025-05-01-preview)." + } + }, + "assignableScopes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. A set of fully qualified Scopes at or below which Role Assignments may be created using this Role Definition. This will allow application of this Role Definition on the entire database account or any underlying Database / Keyspace. Must have at least one element. Scopes higher than Database account are not enforceable as assignable Scopes. Note that resources referenced in assignable Scopes need not exist. Defaults to the current account." + } + }, + "cassandraRoleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/cassandraRoleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of Cassandra Role Assignments to be created for the Cassandra Role Definition." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleDefinition": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]", + "properties": { + "assignableScopes": "[coalesce(parameters('assignableScopes'), createArray(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]", + "permissions": [ + { + "dataActions": "[parameters('dataActions')]", + "notDataActions": "[parameters('notDataActions')]" + } + ], + "roleName": "[parameters('roleName')]", + "type": "CustomRole" + } + }, + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "roleDefinitionId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraRoleDefinition" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cassandra role definition." + }, + "value": "[coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName')))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cassandra role definition." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleDefinitions', parameters('databaseAccountName'), coalesce(parameters('name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), parameters('roleName'))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the cassandra role definition was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "databaseAccount_cassandraRoleAssignments": { + "copy": { + "name": "databaseAccount_cassandraRoleAssignments", + "count": "[length(coalesce(parameters('cassandraRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandra-ra-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'name')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('cassandraRoleAssignments'), createArray())[copyIndex()], 'scope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "14764024820910071147" + }, + "name": "DocumentDB Database Account Cassandra Role Assignments.", + "description": "This module deploys a Cassandra Role Assignment in a CosmosDB Account." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name unique identifier of the Cassandra Role Assignment." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier for the associated AAD principal in the AAD graph to which access is being granted through this Role Assignment. Tenant ID for the principal is inferred using the tenant associated with the subscription." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The unique identifier of the associated Cassandra Role Definition." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The data plane resource path for which access is being granted through this Cassandra Role Assignment. Defaults to the current account." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraRoleAssignment": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]", + "properties": { + "principalId": "[parameters('principalId')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "scope": "[coalesce(parameters('scope'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra Role Assignment." + }, + "value": "[coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra Role Assignment." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraRoleAssignments', parameters('databaseAccountName'), coalesce(parameters('name'), guid(parameters('roleDefinitionId'), parameters('principalId'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra Role Assignment was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount", + "databaseAccount_cassandraKeyspaces", + "databaseAccount_cassandraRoleDefinitions" + ] }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "databaseAccount_mongodbDatabases": { + "copy": { + "name": "databaseAccount_mongodbDatabases", + "count": "[length(coalesce(parameters('mongodbDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "collections": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'collections')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'throughput')]" + }, + "autoscaleSettings": { + "value": "[tryGet(coalesce(parameters('mongodbDatabases'), createArray())[copyIndex()], 'autoscaleSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "13897098552792121791" + }, + "name": "DocumentDB Database Account MongoDB Databases", + "description": "This module deploys a MongoDB Database within a CosmosDB Account." + }, + "definitions": { + "collectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a collection." + } + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the mongodb database." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/definitions/collectionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Collections in the mongodb database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "autoscaleSettings": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2025-04-15#properties/properties/properties/options/properties/autoscaleSettings" + }, + "description": "Optional. Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "mongodbDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput'), 'autoscaleSettings', parameters('autoscaleSettings')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "mongodbDatabase_collections": { + "copy": { + "name": "mongodbDatabase_collections", + "count": "[length(coalesce(parameters('collections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('collections'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "mongodbDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].name]" + }, + "indexes": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].indexes]" + }, + "shardKey": { + "value": "[coalesce(parameters('collections'), createArray())[copyIndex()].shardKey]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('collections'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "16151461445994734468" + }, + "name": "DocumentDB Database Account MongoDB Database Collections", + "description": "This module deploys a MongoDB Database Collection." + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." + } + }, + "mongodbDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the collection." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." + } + }, + "indexes": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/indexes" + }, + "description": "Required. Indexes for the collection." + } + }, + "shardKey": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections@2025-04-15#properties/properties/properties/resource/properties/shardKey" + }, + "description": "Required. ShardKey for the collection." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2025-04-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]", + "indexes": "[parameters('indexes')]", + "shardKey": "[parameters('shardKey')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database collection." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database collection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "mongodbDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the mongodb database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the mongodb database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the mongodb database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "databaseAccount_gremlinDatabases": { + "copy": { + "name": "databaseAccount_gremlinDatabases", + "count": "[length(coalesce(parameters('gremlinDatabases'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "graphs": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'graphs')]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('gremlinDatabases'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11959636451300474346" + }, + "name": "DocumentDB Database Account Gremlin Databases", + "description": "This module deploys a Gremlin Database within a CosmosDB Account." + }, + "definitions": { + "graphType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a graph." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin database resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + } + }, + "graphs": { + "type": "array", + "items": { + "$ref": "#/definitions/graphType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinDatabase": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "gremlinDatabase_gremlinGraphs": { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(coalesce(parameters('graphs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), coalesce(parameters('graphs'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('graphs'), createArray())[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "indexingPolicy": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'indexingPolicy')]" + }, + "partitionKeyPaths": { + "value": "[tryGet(coalesce(parameters('graphs'), createArray())[copyIndex()], 'partitionKeyPaths')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "10487122333182352122" + }, + "name": "DocumentDB Database Accounts Gremlin Databases Graphs", + "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/tags" + }, + "description": "Optional. Tags of the Gremlin graph resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "indexingPolicy": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/indexingPolicy" + }, + "description": "Optional. Indexing policy of the graph." + }, + "nullable": true + }, + "partitionKeyPaths": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs@2025-04-15#properties/properties/properties/resource/properties/partitionKey/properties/paths" + }, + "description": "Optional. List of paths using which data within the container can be partitioned." + }, + "nullable": true + } + }, + "resources": { + "databaseAccount::gremlinDatabase": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "gremlinGraph": { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": "[parameters('indexingPolicy')]", + "partitionKey": { + "paths": "[parameters('partitionKeyPaths')]" + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "gremlinDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "databaseAccount_tables": { + "copy": { + "name": "databaseAccount_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('tables'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "maxThroughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'maxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "1787500858429182824" + }, + "name": "Azure Cosmos DB account tables", + "description": "This module deploys a table within an Azure Cosmos DB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/tables@2025-04-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-04-15", + "name": "[parameters('databaseAccountName')]" + }, + "table": { + "type": "Microsoft.DocumentDB/databaseAccounts/tables", + "apiVersion": "2025-04-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "databaseAccount_cassandraKeyspaces": { + "copy": { + "name": "databaseAccount_cassandraKeyspaces", + "count": "[length(coalesce(parameters('cassandraKeyspaces'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'tables')]" + }, + "views": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'views')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "throughput": { + "value": "[tryGet(coalesce(parameters('cassandraKeyspaces'), createArray())[copyIndex()], 'throughput')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15257396763463366586" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces", + "description": "This module deploys a Cassandra Keyspace within a CosmosDB Account." + }, + "definitions": { + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags for the table." + }, + "nullable": true + }, + "defaultTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Default TTL (Time To Live) in seconds for data in the table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Analytical TTL for the table." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra table." + } + }, + "viewType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the view." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition (CQL statement)." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags for the view." + }, + "nullable": true + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a Cassandra view (materialized view)." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra keyspace." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra keyspace resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cosmos DB account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra tables to deploy in the keyspace." + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/viewType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Cassandra views (materialized views) to deploy in the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the keyspace. If not set, autoscale will be disabled. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. Setting throughput at the keyspace level is only recommended for development/test or when workload across all tables in the shared throughput keyspace is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the table level." + } + } + }, + "resources": { + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraKeyspace": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]", + "resource": { + "id": "[parameters('name')]" + } + }, + "dependsOn": [ + "databaseAccount" + ] + }, + "cassandraKeyspace_tables": { + "copy": { + "name": "cassandraKeyspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandradb-{1}', uniqueString(deployment().name, parameters('name')), parameters('tables')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "schema": { + "value": "[parameters('tables')[copyIndex()].schema]" + }, + "analyticalStorageTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'analyticalStorageTtl')]" + }, + "throughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "defaultTtl": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'defaultTtl')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15998065591386988132" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Tables", + "description": "This module deploys a Cassandra Table within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra table." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/tags" + }, + "description": "Optional. Tags of the Cassandra table resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "schema": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables@2024-11-15#properties/properties/properties/resource/properties/schema" + }, + "description": "Required. Schema definition for the Cassandra table." + } + }, + "analyticalStorageTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Analytical TTL for the table. Default to 0 (disabled). Analytical store is enabled when set to a value other than 0. If set to -1, analytical store retains all historical data." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the table. Cannot be used with throughput. If not specified, the table will inherit throughput from the keyspace." + } + }, + "defaultTtl": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Default time to live in seconds. Default to 0 (disabled). If set to -1, items do not expire." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-11-15", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraTable": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables", + "apiVersion": "2024-11-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "schema": "[parameters('schema')]", + "defaultTtl": "[parameters('defaultTtl')]", + "analyticalStorageTtl": "[parameters('analyticalStorageTtl')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra table." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + }, + "cassandraKeyspace_views": { + "copy": { + "name": "cassandraKeyspace_views", + "count": "[length(parameters('views'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-cassandraview-{1}', uniqueString(deployment().name, parameters('name')), parameters('views')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('views')[copyIndex()].name]" + }, + "cassandraKeyspaceName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "viewDefinition": { + "value": "[parameters('views')[copyIndex()].viewDefinition]" + }, + "throughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'throughput')]" + }, + "autoscaleSettingsMaxThroughput": { + "value": "[tryGet(parameters('views')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('views')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6617803098467821091" + }, + "name": "DocumentDB Database Account Cassandra Keyspaces Views", + "description": "This module deploys a Cassandra View (Materialized View) within a Cassandra Keyspace in a CosmosDB Account." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Cassandra view." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views@2025-05-01-preview#properties/tags" + }, + "description": "Optional. Tags of the Cassandra view resource." + }, + "nullable": true + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "cassandraKeyspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Cassandra Keyspace. Required if the template is used in a standalone deployment." + } + }, + "viewDefinition": { + "type": "string", + "metadata": { + "description": "Required. View definition of the Cassandra view. This is the CQL statement that defines the materialized view." + } + }, + "throughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Request units per second. Cannot be used with autoscaleSettingsMaxThroughput." + } + }, + "autoscaleSettingsMaxThroughput": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Maximum autoscale throughput for the view. Cannot be used with throughput." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "resources": { + "databaseAccount::cassandraKeyspace": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'))]" + }, + "databaseAccount": { + "existing": true, + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('databaseAccountName')]" + }, + "cassandraView": { + "type": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views", + "apiVersion": "2025-05-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "viewDefinition": "[parameters('viewDefinition')]" + }, + "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(and(equals(parameters('throughput'), null()), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null()), 'throughput', parameters('throughput')))]" + }, + "dependsOn": [ + "databaseAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra view." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra view." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/views', parameters('databaseAccountName'), parameters('cassandraKeyspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra view was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "cassandraKeyspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Cassandra keyspace." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cassandra keyspace." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Cassandra keyspace was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "databaseAccount" + ] }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "databaseAccount_privateEndpoints": { + "copy": { + "name": "databaseAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-dbAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private dns zone group." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } } }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } + "dependsOn": [ + "databaseAccount" + ] } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the database account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the database account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the database account was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('databaseAccount', '2025-04-15', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('databaseAccount', '2025-04-15', 'full').location]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the database account." + }, + "value": "[reference('databaseAccount').documentEndpoint]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "primaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryMasterKey]" + }, + "primaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The primary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').primaryReadonlyMasterKey]" + }, + "primaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[0].connectionString]" + }, + "primaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The primary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[2].connectionString]" + }, + "secondaryReadWriteKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryMasterKey]" + }, + "secondaryReadOnlyKey": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only key." + }, + "value": "[listKeys('databaseAccount', '2025-04-15').secondaryReadonlyMasterKey]" + }, + "secondaryReadWriteConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-write connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[1].connectionString]" + }, + "secondaryReadOnlyConnectionString": { + "type": "securestring", + "metadata": { + "description": "The secondary read-only connection string." + }, + "value": "[listConnectionStrings('databaseAccount', '2025-04-15').connectionStrings[3].connectionString]" + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } } } }, - "parameters": { - "name": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Required. Name of the Container App." - } + "description": "Resource ID of the Cosmos DB account." + }, + "value": "[reference('cosmosAccount').outputs.resourceId.value]" }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." - } + "description": "Name of the Cosmos DB account." + }, + "value": "[reference('cosmosAccount').outputs.name.value]" }, - "kind": { + "connectionString": { "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } + "description": "MongoDB connection string (without credentials — use Key Vault for secrets)." + }, + "value": "[format('mongodb+srv://{0}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000', parameters('name'))]" }, - "clientCertificateMode": { + "primaryReadWriteConnectionString": { "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } + "description": "Primary read-write connection string from the Cosmos DB account." + }, + "value": "[listOutputsWithSecureValues('cosmosAccount', '2025-04-01').primaryReadWriteConnectionString]" }, - "stickySessionsAffinity": { + "endpoint": { "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } + "description": "Endpoint of the Cosmos DB account." + }, + "value": "[format('https://{0}.mongo.cosmos.azure.com:443/', parameters('name'))]" }, - "ingressTransport": { + "databaseName": { "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." + "description": "Database name." }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" + "value": "[parameters('databaseName')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').cosmosDB), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": { + "app": "[variables('solutionSuffix')]", + "location": "[parameters('location')]" + } + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "sku": { + "value": "Standard" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value, ''), 'logCategoriesAndGroups', createArray(createObject('categoryGroup', 'allLogs', 'enabled', true()))))), createObject('value', null()))]", + "disableLocalAuth": { + "value": false + }, + "replicaLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('replicaLocation', variables('replicaLocation')))), createObject('value', createArray()))]", + "roleAssignments": { + "value": [ + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" }, - "metadata": { - "description": "Optional. The scaling settings of the service." + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" + }, + { + "principalId": "[tryGet(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs, 'systemAssignedMIPrincipalId'), 'value')]", + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalType": "ServicePrincipal" } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" + ] + }, + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_PROCESS", + "value": "Processes" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMA", + "value": "Schemas" + }, + { + "name": "APP_COSMOS_DATABASE", + "value": "ContentProcess" + }, + { + "name": "APP_CPS_CONFIGURATION", + "value": "cps-configuration" + }, + { + "name": "APP_CPS_MAX_FILESIZE_MB", + "value": "20" + }, + { + "name": "APP_CPS_PROCESSES", + "value": "cps-processes" + }, + { + "name": "APP_MESSAGE_QUEUE_EXTRACT", + "value": "content-pipeline-extract-queue" + }, + { + "name": "APP_MESSAGE_QUEUE_INTERVAL", + "value": "5" + }, + { + "name": "APP_MESSAGE_QUEUE_PROCESS_TIMEOUT", + "value": "180" + }, + { + "name": "APP_MESSAGE_QUEUE_VISIBILITY_TIMEOUT", + "value": "10" + }, + { + "name": "APP_PROCESS_STEPS", + "value": "extract,map,evaluate,save" + }, + { + "name": "APP_STORAGE_BLOB_URL", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.blob]" + }, + { + "name": "APP_STORAGE_QUEUE_URL", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[coalesce(tryGet(reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.aiProjectInfo.value, 'apiEndpoint'), '')]" + }, + { + "name": "APP_COSMOS_CONNSTR", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.primaryReadWriteConnectionString.value]" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCH_PROCESS", + "value": "claimprocesses" + }, + { + "name": "APP_COSMOS_CONTAINER_BATCHES", + "value": "batches" + }, + { + "name": "APP_COSMOS_CONTAINER_SCHEMASET", + "value": "Schemasets" + }, + { + "name": "APP_CPS_PROCESS_BATCH", + "value": "process-batch" + }, + { + "name": "APP_CPS_CONTENT_PROCESS_ENDPOINT", + "value": "[format('http://{0}/', reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value)]" + }, + { + "name": "APP_CPS_POLL_INTERVAL_SECONDS", + "value": "3" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "CLAIM_PROCESS_QUEUE_NAME", + "value": "claim-process-queue" + }, + { + "name": "DEAD_LETTER_QUEUE_NAME", + "value": "claim-process-dead-letter-queue" + }, + { + "name": "AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", + "value": "[parameters('gptModelName')]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_OPENAI_ENDPOINT_BASE", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", + "value": "" + }, + { + "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", + "value": "" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + }, + { + "name": "GLOBAL_LLM_SERVICE", + "value": "AzureOpenAI" + }, + { + "name": "GPT5_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "GPT5_CHAT_DEPLOYMENT_NAME", + "value": "gpt-5" + }, + { + "name": "GPT5_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "PHI4_API_VERSION", + "value": "2024-05-01-preview" + }, + { + "name": "PHI4_CHAT_DEPLOYMENT_NAME", + "value": "phi-4" + }, + { + "name": "PHI4_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" } - }, - "activeRevisionsMode": { + ] + }, + "publicNetworkAccess": { + "value": "Enabled" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "8501097744482672663" + } + }, + "parameters": { + "name": { "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." + "description": "Name of the App Configuration store." } }, - "environmentResourceId": { + "location": { "type": "string", "metadata": { - "description": "Required. Resource ID of environment." + "description": "Azure region for the resource." } }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Whether purge protection is enabled." } }, "tags": { "type": "object", + "defaultValue": {}, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Tags to apply to the resource." } }, "enableTelemetry": { @@ -64957,334 +69077,122 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { + "managedIdentities": { "type": "object", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." + "description": "Managed identity configuration." } }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", + "sku": { + "type": "string", + "defaultValue": "Standard", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." + "description": "SKU for the App Configuration store." } }, - "terminationGracePeriodSeconds": { - "type": "int", + "diagnosticSettings": { + "type": "array", "nullable": true, "metadata": { - "description": "Optional. The termination grace period for the container app." + "description": "Optional. Diagnostic settings to apply to the App Configuration store." } }, - "initContainersTemplate": { - "type": "array", + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true + "description": "Whether local authentication is disabled." + } }, - "secrets": { + "replicaLocations": { "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The secrets of the Container App." + "description": "Optional. Replica locations for the App Configuration store." } }, - "revisionSuffix": { - "type": "string", - "nullable": true, + "roleAssignments": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." + "description": "Role assignments for the App Configuration store." } }, - "volumes": { + "keyValues": { "type": "array", + "defaultValue": [], "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." + "description": "Key-values to create in the App Configuration store." } }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Optional. The name of the Container App Auth configs." + "description": "Public network access setting." } }, - "diagnosticSettings": { + "privateEndpoints": { "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, + "defaultValue": [], "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Private endpoint configuration." } } }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", + "appConfiguration": { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", + "name": "[take(format('avm.res.app-configuration.configuration-store.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "containerAppName": { + "name": { "value": "[parameters('name')]" }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" + "replicaLocations": { + "value": "[parameters('replicaLocations')]" }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" + "roleAssignments": { + "value": "[parameters('roleAssignments')]" }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" + "keyValues": { + "value": "[parameters('keyValues')]" }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" } }, "template": { @@ -65294,1917 +69202,2229 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" + "version": "0.37.4.10188", + "templateHash": "396653159019145335" }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." }, - "parameters": { - "containerAppName": { - "type": "string", + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } } }, - "encryptionSettings": { + "lockType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } }, - "nullable": true - }, - "httpSettings": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } }, - "identityProviders": { + "managedIdentityAllType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } }, - "nullable": true - }, - "login": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "platform": { + "privateEndpointSingleServiceType": { "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", + "roleAssignmentType": { + "type": "object", "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" - ] - }, - "avmContainerApp_API_update": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-api.update.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('ca-{0}-api', variables('solutionSuffix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, - "tags": { - "value": "[parameters('tags')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } - }, - "containers": { - "value": [ - { - "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" - }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorAPI" - } - ], - "probes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 - } - ] - } - ] - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "100" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } } - } - } - ] - } - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressTransport": { - "value": "auto" - }, - "ingressAllowInsecure": { - "value": false - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "*" - ], - "allowedMethods": [ - "GET", - "POST", - "PUT", - "DELETE", - "OPTIONS" - ], - "allowedHeaders": [ - "Authorization", - "Content-Type", - "*" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." }, - "parameters": { - "containerAppName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." - } - }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "description": "The name of the app configuration." }, - "nullable": true + "value": "[parameters('name')]" }, - "identityProviders": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "description": "The resource ID of the app configuration." }, - "nullable": true + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" }, - "login": { - "type": "object", + "resourceGroupName": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "description": "The resource group the app configuration store was deployed into." }, - "nullable": true + "value": "[resourceGroup().name]" }, - "platform": { - "type": "object", + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "The principal ID of the system assigned identity." }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { + "location": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "The location the resource was deployed into." }, - "value": "current" + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" }, - "resourceId": { + "endpoint": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "The endpoint of the app configuration." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference('configurationStore').endpoint]" }, - "resourceGroupName": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "The private endpoints of the app configuration." }, - "value": "[resourceGroup().name]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } - }, - "dependsOn": [ - "containerApp" - ] + } } }, "outputs": { "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Container App." + "description": "Resource ID of the App Configuration store." }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" + "value": "[reference('appConfiguration').outputs.resourceId.value]" }, "name": { "type": "string", "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "Name of the App Configuration store." }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + "value": "[reference('appConfiguration').outputs.name.value]" }, - "location": { + "endpoint": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "Endpoint of the App Configuration store." }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[reference('appConfiguration').outputs.endpoint.value]" } } } }, "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader", - "cognitiveServicePrivateEndpoint" + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics-workspace.{0}', variables('solutionSuffix')), 64))]" ] }, - "avmContainerApp_Workflow_update": { + { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('avm.res.app.container-app-wkfl.update.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.app-configuration.update.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -67212,90 +71432,39 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]" + "value": "[format('appcs-{0}', variables('solutionSuffix'))]" }, "location": { "value": "[parameters('location')]" }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "environmentResourceId": { - "value": "[reference('avmContainerAppEnv').outputs.resourceId.value]" - }, - "workloadProfileName": { - "value": "Consumption" - }, - "registries": { - "value": null - }, "tags": { "value": "[parameters('tags')]" }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('avmContainerRegistryReader').outputs.resourceId.value]" - ] - } + "publicNetworkAccess": { + "value": "Disabled" }, - "containers": { + "privateEndpoints": { "value": [ { - "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", - "resources": { - "cpu": 4, - "memory": "8.0Gi" + "name": "[format('pep-appconfig-{0}', variables('solutionSuffix'))]", + "customNetworkInterfaceName": "[format('nic-appconfig-{0}', variables('solutionSuffix'))]", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "name": "appconfig-dns-zone-group", + "privateDnsZoneResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').appConfig), 64)), '2025-04-01').outputs.resourceId.value]" + } + ] }, - "env": [ - { - "name": "APP_CONFIG_ENDPOINT", - "value": "[reference('avmAppConfig').outputs.endpoint.value]" - }, - { - "name": "APP_ENV", - "value": "prod" - }, - { - "name": "APP_LOGGING_LEVEL", - "value": "INFO" - }, - { - "name": "AZURE_PACKAGE_LOGGING_LEVEL", - "value": "WARNING" - }, - { - "name": "AZURE_LOGGING_PACKAGES", - "value": "" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[if(parameters('enableMonitoring'), reference('applicationInsights').outputs.connectionString.value, '')]" - }, - { - "name": "OTEL_SERVICE_NAME", - "value": "ContentProcessorWorkflow" - } - ] + "subnetResourceId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.backendSubnetResourceId.value]" } ] - }, - "activeRevisionsMode": { - "value": "Single" - }, - "ingressExternal": { - "value": false - }, - "disableIngress": { - "value": true - }, - "scaleSettings": { - "value": { - "maxReplicas": "[if(parameters('enableScalability'), 3, 2)]", - "minReplicas": "[if(parameters('enableScalability'), 2, 1)]" - } } }, "template": { @@ -67306,1611 +71475,2459 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "12626366001403616495" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." + "templateHash": "8501097744482672663" + } }, - "definitions": { - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, + "parameters": { + "name": { + "type": "string", "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." + "description": "Name of the App Configuration store." } }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, + "location": { + "type": "string", "metadata": { - "description": "The type for a service binding." + "description": "Azure region for the resource." } }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." + "description": "Whether purge protection is enabled." } }, - "containerAppProbeType": { + "tags": { "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, + "defaultValue": {}, "metadata": { - "description": "The type for a container app probe." + "description": "Tags to apply to the resource." } }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "containerAppProbeHttpGetType": { + "managedIdentities": { "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, + "nullable": true, "metadata": { - "description": "The type for a container app probe HTTP GET." + "description": "Managed identity configuration." } }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, + "sku": { + "type": "string", + "defaultValue": "Standard", "metadata": { - "description": "The type for a container app probe HTTP GET header." + "description": "SKU for the App Configuration store." } }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, + "diagnosticSettings": { + "type": "array", + "nullable": true, "metadata": { - "description": "The type for a container app probe TCP socket." + "description": "Optional. Diagnostic settings to apply to the App Configuration store." } }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether local authentication is disabled." + } + }, + "replicaLocations": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The scale settings for the Container App." + "description": "Optional. Replica locations for the App Configuration store." } }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, + "roleAssignments": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The scaling rules for the Container App." + "description": "Role assignments for the App Configuration store." } }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, + "keyValues": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The type for a volume mount." + "description": "Key-values to create in the App Configuration store." } }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." + "description": "Public network access setting." } }, - "authConfigType": { - "type": "object", + "privateEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Private endpoint configuration." + } + } + }, + "resources": { + "appConfiguration": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.app-configuration.configuration-store.{0}', parameters('name')), 64)]", "properties": { - "encryptionSettings": { - "type": "object", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "replicaLocations": { + "value": "[parameters('replicaLocations')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "keyValues": { + "value": "[parameters('keyValues')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "396653159019145335" + }, + "name": "App Configuration Stores", + "description": "This module deploys an App Configuration Store." + }, + "definitions": { + "dataPlaneProxyType": { + "type": "object", + "properties": { + "authenticationMode": { + "type": "string", + "allowedValues": [ + "Local", + "Pass-through" + ], + "nullable": true, + "metadata": { + "description": "Optional. The data plane proxy authentication mode. This property manages the authentication mode of request to the data plane resources. 'Pass-through' is recommended." + } + }, + "privateLinkDelegation": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. The data plane proxy private link delegation. This property manages if a request from delegated Azure Resource Manager (ARM) private link is allowed when the data plane resource requires private link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data plane proxy." + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "replicaLocationType": { + "type": "object", + "properties": { + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the replica." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a replica location" + } + }, + "_1.lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "_1.roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/_1.lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure App Configuration." + } }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "diagnosticSettingMetricsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Developer", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Pricing tier of App Configuration." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], + "metadata": { + "description": "Optional. Indicates whether the configuration store need to be recovered." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disables all authentication methods other than AAD authentication." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property specifying whether protection against purge is enabled for this configuration store. Defaults to true unless sku is set to Free, since purge protection is not available in Free tier." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 7, + "metadata": { + "description": "Optional. The amount of time in days that the configuration store will be retained when it is soft deleted." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "keyValues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All Key / Values to create. Requires local authentication to be enabled." + } + }, + "replicaLocations": { + "type": "array", + "items": { + "$ref": "#/definitions/replicaLocationType" }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "nullable": true, + "metadata": { + "description": "Optional. All Replicas to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.AppConfiguration/configurationStores@2024-05-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "dataPlaneProxy": { + "$ref": "#/definitions/dataPlaneProxyType", + "nullable": true, + "metadata": { + "description": "Optional. Property specifying the configuration of data plane proxy for Azure Resource Manager (ARM)." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "notes": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the notes of the lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "defaultValue": "containerapps", - "allowedValues": [ - "containerapps", - "workflowapp", - "functionapp" - ], - "metadata": { - "description": "Optional. Metadata used to render different experiences for resources of the same type." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/tags" - }, - "description": "Optional. Tags of the resource." - }, - "nullable": true - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "traffic": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/ingress/properties/traffic" - }, - "description": "Optional. Traffic weight configuration for routing traffic across revisions. Each entry specifies a revision (or latest) and its traffic percentage. Supports blue-green and canary deployment patterns." - }, - "nullable": true - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/containers" - }, - "description": "Required. List of container definitions for the Container App." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The termination grace period for the container app." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2026-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(variables('formattedUserAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(variables('formattedUserAssignedIdentities'))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.22.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "terminationGracePeriodSeconds": "[parameters('terminationGracePeriodSeconds')]", - "initContainers": "[parameters('initContainersTemplate')]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(parameters('includeAddOns'), parameters('serviceBinds'), null())]", - "volumes": "[parameters('volumes')]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[parameters('dapr')]", - "identitySettings": "[parameters('identitySettings')]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', parameters('customDomains'), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', parameters('ipSecurityRestrictions'), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('traffic'), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(parameters('includeAddOns'), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[parameters('registries')]", - "secrets": "[parameters('secrets')]", - "runtime": "[parameters('runtime')]" - } - } - }, - "containerApp_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.App/containerApps', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "enableReferencedModulesTelemetry": false, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "App Configuration Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '175b81b9-6e0d-490a-85e4-0d422273c10c')]", + "App Configuration Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fe86443c-f201-4fc4-9d2a-ac61149fbda0')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2024-11-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.appconfiguration-configurationstore.{0}.{1}', replace('0.9.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2024-12-01-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2024-11-30", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "configurationStore": { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "enablePurgeProtection": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), false(), parameters('enablePurgeProtection'))]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keyVaultProperties', createObject('keyIdentifier', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), reference('cMKKeyVault::cMKKey').keyUri, reference('cMKKeyVault::cMKKey').keyUriWithVersion)), 'identityClientId', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), reference('cMKUserAssignedIdentity').clientId, null()))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", + "softDeleteRetentionInDays": "[if(or(equals(parameters('sku'), 'Free'), equals(parameters('sku'), 'Developer')), 0, parameters('softDeleteRetentionInDays'))]", + "dataPlaneProxy": "[if(not(empty(parameters('dataPlaneProxy'))), createObject('authenticationMode', coalesce(tryGet(parameters('dataPlaneProxy'), 'authenticationMode'), 'Pass-through'), 'privateLinkDelegation', parameters('dataPlaneProxy').privateLinkDelegation), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "configurationStore_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_diagnosticSettings": { + "copy": { + "name": "configurationStore_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_roleAssignments": { + "copy": { + "name": "configurationStore_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_keyValues": { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(coalesce(parameters('keyValues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-KeyValues-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('keyValues'), createArray())[copyIndex()].value]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keyValues'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "4166303424618131775" + }, + "name": "App Configuration Stores Key Values", + "description": "This module deploys an App Configuration Store Key Value." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the key-value." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "appConfiguration": { + "existing": true, + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2025-02-01-preview", + "name": "[parameters('appConfigurationName')]" + }, + "keyValues": { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_replicas": { + "copy": { + "name": "configurationStore_replicas", + "count": "[length(coalesce(parameters('replicaLocations'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppConfig-Replicas-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[parameters('name')]" + }, + "replicaLocation": { + "value": "[coalesce(parameters('replicaLocations'), createArray())[copyIndex()].replicaLocation]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('replicaLocations'), createArray())[copyIndex()], 'name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "12609356088985615301" + }, + "name": "App Configuration Replicas", + "description": "This module deploys an App Configuration Replica." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}replica', parameters('replicaLocation'))]", + "metadata": { + "description": "Optional. Name of the replica." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "replicaLocation": { + "type": "string", + "metadata": { + "description": "Required. Location of the replica." + } + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/replicas", + "apiVersion": "2025-02-01-preview", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), parameters('name'))]", + "location": "[parameters('replicaLocation')]" + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the app configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the replica that was deployed." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replica that was deployed." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/replicas', parameters('appConfigurationName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] + }, + "configurationStore_privateEndpoints": { + "copy": { + "name": "configurationStore_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-configStore-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'configurationStores')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "configurationStore" + ] } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "4649255393182983719" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { + "outputs": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." - } - }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." + "description": "The name of the app configuration." }, - "nullable": true + "value": "[parameters('name')]" }, - "identityProviders": { - "type": "object", + "resourceId": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." + "description": "The resource ID of the app configuration." }, - "nullable": true + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" }, - "login": { - "type": "object", + "resourceGroupName": { + "type": "string", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." + "description": "The resource group the app configuration store was deployed into." }, - "nullable": true + "value": "[resourceGroup().name]" }, - "platform": { - "type": "object", + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2026-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." + "description": "The principal ID of the system assigned identity." }, - "nullable": true - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.app-containerapp-authconfig.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } + "value": "[tryGet(tryGet(reference('configurationStore', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" }, - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2026-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2026-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { + "location": { "type": "string", "metadata": { - "description": "The name of the set of Container App Auth configs." + "description": "The location the resource was deployed into." }, - "value": "current" + "value": "[reference('configurationStore', '2025-02-01-preview', 'full').location]" }, - "resourceId": { + "endpoint": { "type": "string", "metadata": { - "description": "The resource ID of the set of Container App Auth configs." + "description": "The endpoint of the app configuration." }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" + "value": "[reference('configurationStore').endpoint]" }, - "resourceGroupName": { - "type": "string", + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, "metadata": { - "description": "The resource group containing the set of Container App Auth configs." + "description": "The private endpoints of the app configuration." }, - "value": "[resourceGroup().name]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('configurationStore_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } - }, - "dependsOn": [ - "containerApp" - ] + } } }, "outputs": { "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." + "description": "Resource ID of the App Configuration store." }, - "value": "[resourceGroup().name]" + "value": "[reference('appConfiguration').outputs.resourceId.value]" }, "name": { "type": "string", "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "Name of the App Configuration store." }, - "value": "[tryGet(tryGet(reference('containerApp', '2026-01-01', 'full'), 'identity'), 'principalId')]" + "value": "[reference('appConfiguration').outputs.name.value]" }, - "location": { + "endpoint": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "Endpoint of the App Configuration store." }, - "value": "[reference('containerApp', '2026-01-01', 'full').location]" + "value": "[reference('appConfiguration').outputs.endpoint.value]" } } } }, "dependsOn": [ - "applicationInsights", - "avmAppConfig", - "avmContainerAppEnv", - "avmContainerRegistryReader" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', variables('solutionSuffix')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.private-dns-zone.{0}.{1}', variables('solutionSuffix'), variables('dnsZoneIndex').appConfig), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.virtual-network.{0}', variables('solutionSuffix')), 64))]" ] } - }, + ], "outputs": { "CONTAINER_WEB_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for Web App." }, - "value": "[reference('avmContainerApp_Web').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_API_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for API." }, - "value": "[reference('avmContainerApp_API').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WEB_APP_FQDN": { "type": "string", "metadata": { "description": "The FQDN of the Container App." }, - "value": "[reference('avmContainerApp_Web').outputs.fqdn.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.fqdn.value]" }, "CONTAINER_API_APP_FQDN": { "type": "string", "metadata": { "description": "The FQDN of the Container App API." }, - "value": "[reference('avmContainerApp_API').outputs.fqdn.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.fqdn.value]" }, "CONTAINER_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for APP." }, - "value": "[reference('avmContainerApp').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-processor.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", "metadata": { "description": "The name of the Container App used for Workflow." }, - "value": "[reference('avmContainerApp_Workflow').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_APP_USER_IDENTITY_ID": { "type": "string", "metadata": { "description": "The user identity resource ID used fot the Container APP." }, - "value": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" }, "CONTAINER_APP_USER_PRINCIPAL_ID": { "type": "string", "metadata": { "description": "The user identity Principal ID used fot the Container APP." }, - "value": "[reference('avmContainerRegistryReader').outputs.principalId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity-acr.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" }, "CONTAINER_REGISTRY_NAME": { "type": "string", "metadata": { "description": "The name of the Azure Container Registry." }, - "value": "[reference('avmContainerRegistry').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_REGISTRY_LOGIN_SERVER": { "type": "string", "metadata": { "description": "The login server of the Azure Container Registry." }, - "value": "[reference('avmContainerRegistry').outputs.loginServer.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" }, "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { "type": "string", "metadata": { "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA." }, - "value": "[reference('avmAiServices').outputs.name.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-services.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" }, "AZURE_RESOURCE_GROUP": { "type": "string", @@ -68930,7 +73947,7 @@ } } }, - { + "bicepDeployment": { "condition": "[variables('isBicep')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", @@ -68944,6 +73961,9 @@ "solutionName": { "value": "[parameters('solutionName')]" }, + "solutionUniqueText": { + "value": "[parameters('solutionUniqueText')]" + }, "location": { "value": "[parameters('location')]" }, @@ -68953,6 +73973,21 @@ "gptModelName": { "value": "[parameters('gptModelName')]" }, + "deploymentType": { + "value": "[parameters('deploymentType')]" + }, + "gptModelVersion": { + "value": "[parameters('gptModelVersion')]" + }, + "gptDeploymentCapacity": { + "value": "[parameters('gptDeploymentCapacity')]" + }, + "existingLogAnalyticsWorkspaceId": { + "value": "[parameters('existingLogAnalyticsWorkspaceId')]" + }, + "existingFoundryProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" + }, "containerRegistryEndpoint": { "value": "[parameters('containerRegistryEndpoint')]" }, @@ -68988,482 +74023,247 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "6422306545253132015" - }, - "name": "Content Processing Solution Accelerator - Bicep", - "description": "Deploys Content Processing resources using the restored private-repo module interfaces." + "templateHash": "10242238019010929374" + } }, "parameters": { "solutionName": { "type": "string", "defaultValue": "cps", "minLength": 3, - "maxLength": 20 + "maxLength": 20, + "metadata": { + "description": "Optional. Name of the solution to deploy. This should be 3-20 characters long." + } + }, + "solutionUniqueText": { + "type": "string", + "defaultValue": "[substring(uniqueString(subscription().id, resourceGroup().name, parameters('solutionName')), 0, 5)]", + "maxLength": 5, + "metadata": { + "description": "Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources." + } }, "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { "azd": { "type": "location" - } + }, + "description": "Required. Azure region for all services." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." } }, "azureAiServiceLocation": { "type": "string", + "allowedValues": [ + "australiaeast", + "eastus", + "eastus2", + "japaneast", + "southcentralus", + "southeastasia", + "swedencentral", + "uksouth", + "westeurope", + "westus", + "westus3" + ], "metadata": { "azd": { - "type": "location" - } + "type": "location", + "usageName": [ + "OpenAI.GlobalStandard.gpt-5.1,300" + ] + }, + "description": "Required. Location for the Azure AI Services deployment." + }, + "minLength": 1 + }, + "deploymentType": { + "type": "string", + "defaultValue": "GlobalStandard", + "allowedValues": [ + "Standard", + "GlobalStandard" + ], + "metadata": { + "description": "Optional. Type of GPT deployment to use: Standard | GlobalStandard." } }, "gptModelName": { "type": "string", - "defaultValue": "gpt-5.1" + "defaultValue": "gpt-5.1", + "metadata": { + "description": "Optional. Name of the GPT model to deploy." + } + }, + "gptModelVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Version of the GPT model to deploy. Empty string uses the latest available version." + } + }, + "gptDeploymentCapacity": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. Capacity of the GPT deployment." + } }, "containerRegistryEndpoint": { "type": "string", - "defaultValue": "" + "defaultValue": "cpscontainerreg.azurecr.io", + "metadata": { + "description": "Optional. The container registry login server or endpoint for the container images." + } }, "imageTag": { "type": "string", - "defaultValue": "latest_v2" + "defaultValue": "latest_v2", + "metadata": { + "description": "Optional. The image tag for the container images." + } }, "enablePrivateNetworking": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable private networking for the deployment." + } }, "enableMonitoring": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable monitoring applicable resources." + } }, "enableRedundancy": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable redundancy for applicable resources." + } }, "enableScalability": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Enable scalability for applicable resources." + } }, "enableTelemetry": { "type": "bool", - "defaultValue": true + "defaultValue": true, + "metadata": { + "description": "Optional. Enable or disable usage telemetry for the deployment." + } }, "enablePurgeProtection": { "type": "bool", - "defaultValue": false - }, - "tags": { - "type": "object", - "defaultValue": { - "app": "Content Processing Solution Accelerator", - "location": "[resourceGroup().location]" - } - } - }, - "variables": { - "uniqueToken": "[substring(uniqueString(subscription().subscriptionId, resourceGroup().id, parameters('solutionName')), 0, 5)]", - "solutionSuffix": "[toLower(replace(replace(replace(format('{0}{1}', parameters('solutionName'), variables('uniqueToken')), '-', ''), '_', ''), '.', ''))]", - "managedIdentityName": "[format('id-{0}', variables('solutionSuffix'))]", - "containerRegistryName": "[replace(format('cr{0}', variables('solutionSuffix')), '-', '')]", - "storageAccountName": "[take(replace(format('st{0}', variables('solutionSuffix')), '-', ''), 24)]", - "cosmosDbName": "[format('cosmos-{0}', variables('solutionSuffix'))]", - "cosmosDatabaseName": "contentprocessing", - "cosmosContainerName": "documents", - "aiServicesName": "[format('aif-{0}', variables('solutionSuffix'))]", - "aiProjectName": "[format('proj-{0}', variables('solutionSuffix'))]", - "aiSearchName": "[format('srch-{0}', variables('solutionSuffix'))]", - "appConfigurationName": "[format('appcs-{0}', variables('solutionSuffix'))]", - "containerAppEnvironmentName": "[format('cae-{0}', variables('solutionSuffix'))]", - "contentProcessorAppName": "[format('ca-{0}-app', variables('solutionSuffix'))]", - "contentProcessorApiName": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "contentProcessorWebName": "[format('ca-{0}-web', variables('solutionSuffix'))]", - "contentProcessorWorkflowName": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "modelDeploymentName": "[format('gpt-{0}', variables('solutionSuffix'))]", - "storageContainerName": "content", - "storageQueueName": "content", - "acrPullRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", - "storageBlobDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "storageQueueDataContributorRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", - "appConfigurationDataReaderRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "cognitiveServicesOpenAiUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "cognitiveServicesUserRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "azureAiDeveloperRoleId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "cosmosDbEndpoint": "[format('https://{0}.mongo.cosmos.azure.com:443/', variables('cosmosDbName'))]", - "apiProbes": [ - { - "type": "Liveness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Readiness", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 5, - "periodSeconds": 10, - "failureThreshold": 3 - }, - { - "type": "Startup", - "httpGet": { - "path": "/startup", - "port": 80, - "scheme": "HTTP" - }, - "initialDelaySeconds": 20, - "periodSeconds": 5, - "failureThreshold": 10 + "defaultValue": false, + "metadata": { + "description": "Optional. Enable purge protection." } - ] - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2025-08-01", - "name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]" }, - { - "type": "Microsoft.Storage/storageAccounts/queueServices/queues", - "apiVersion": "2025-08-01", - "name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', variables('storageQueueName'))]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageAccountName'), 'default')]" - ] - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2023-04-15", - "name": "[variables('cosmosDbName')]", - "location": "[parameters('location')]", - "kind": "MongoDB", - "tags": "[parameters('tags')]", - "properties": { - "databaseAccountOfferType": "Standard", - "locations": [ - { - "locationName": "[parameters('location')]", - "failoverPriority": 0, - "isZoneRedundant": "[parameters('enableRedundancy')]" - } - ], - "capabilities": [ - { - "name": "EnableMongo" - } - ], - "apiProperties": { - "serverVersion": "7.0" - }, - "disableLocalAuth": false, - "enableAutomaticFailover": false, - "enableMultipleWriteLocations": false, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), 'Disabled', 'Enabled')]" + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Existing Log Analytics Workspace resource ID." } }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", - "apiVersion": "2023-04-15", - "name": "[format('{0}/{1}', variables('cosmosDbName'), variables('cosmosDatabaseName'))]", - "properties": { - "resource": { - "id": "[variables('cosmosDatabaseName')]" - }, - "options": {} - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]" - ] - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", - "apiVersion": "2023-04-15", - "name": "[format('{0}/{1}/{2}', variables('cosmosDbName'), variables('cosmosDatabaseName'), variables('cosmosContainerName'))]", - "properties": { - "resource": { - "id": "[variables('cosmosContainerName')]", - "shardKey": { - "id": "Hash" - }, - "indexes": [ - { - "key": { - "keys": [ - "_id" - ] - } - } - ] - }, - "options": {} - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', variables('cosmosDbName'), variables('cosmosDatabaseName'))]" - ] - }, - { - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', variables('aiServicesName'), variables('aiProjectName'))]", - "location": "[parameters('azureAiServiceLocation')]", - "kind": "AIServices", - "identity": { - "type": "SystemAssigned" - }, - "tags": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]", - "properties": {} - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.ContainerRegistry/registries', variables('containerRegistryName'))]", - "name": "[guid(variables('containerRegistryName'), variables('managedIdentityName'), 'acr-pull')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('acrPullRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'blob')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'blob')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'blob')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageBlobDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorAppName'), 'queue')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorApiName'), 'queue')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", - "name": "[guid(variables('storageAccountName'), variables('contentProcessorWorkflowName'), 'queue')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('storageQueueDataContributorRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorAppName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorApiName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWebName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigurationName'))]", - "name": "[guid(variables('appConfigurationName'), variables('contentProcessorWorkflowName'), 'appconfig')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('appConfigurationDataReaderRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'openai-user')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'openai-user')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesOpenAiUserRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'ai-developer')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'ai-developer')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('azureAiDeveloperRoleId')]" + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Existing Azure AI Foundry project resource ID." + } + } + }, + "variables": { + "solutionSuffix": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueText')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", + "deployerInfo": "[deployer()]", + "createdBy": "[if(contains(variables('deployerInfo'), 'userPrincipalName'), split(variables('deployerInfo').userPrincipalName, '@')[0], variables('deployerInfo').objectId)]", + "existingTags": "[coalesce(resourceGroup().tags, createObject())]", + "containerRegistryName": "[replace(format('cr{0}', variables('solutionSuffix')), '-', '')]", + "storageAccountName": "[take(replace(format('st{0}', variables('solutionSuffix')), '-', ''), 24)]", + "cosmosDbName": "[format('cosmos-{0}', variables('solutionSuffix'))]", + "cosmosDatabaseName": "contentprocessing", + "cosmosContainerName": "documents", + "aiServicesName": "[format('aif-{0}', variables('solutionSuffix'))]", + "aiProjectName": "[format('proj-{0}', variables('solutionSuffix'))]", + "appConfigurationName": "[format('appcs-{0}', variables('solutionSuffix'))]", + "containerAppEnvironmentName": "[format('cae-{0}', variables('solutionSuffix'))]", + "contentProcessorAppName": "[format('ca-{0}-app', variables('solutionSuffix'))]", + "contentProcessorApiName": "[format('ca-{0}-api', variables('solutionSuffix'))]", + "contentProcessorWebName": "[format('ca-{0}-web', variables('solutionSuffix'))]", + "contentProcessorWorkflowName": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", + "modelDeploymentName": "[format('gpt-{0}', variables('solutionSuffix'))]", + "storageContainerName": "content", + "storageQueueName": "content", + "useExternalRegistry": "[not(empty(parameters('containerRegistryEndpoint')))]", + "apiProbes": [ + { + "type": "Liveness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorAppName'), 'cog-user')]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" + { + "type": "Readiness", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 5, + "periodSeconds": 10, + "failureThreshold": 3 }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64))]" - ] - }, + { + "type": "Startup", + "httpGet": { + "path": "/startup", + "port": 80, + "scheme": "HTTP" + }, + "initialDelaySeconds": 20, + "periodSeconds": 5, + "failureThreshold": 10 + } + ], + "resourceTags": "[union(variables('existingTags'), parameters('tags'), createObject('TemplateName', 'Content Processing', 'CreatedBy', variables('createdBy'), 'DeploymentName', deployment().name, 'Type', 'Non-WAF'))]" + }, + "resources": [ { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiServicesName'))]", - "name": "[guid(variables('aiServicesName'), variables('contentProcessorWorkflowName'), 'cog-user')]", + "type": "Microsoft.Resources/tags", + "apiVersion": "2025-04-01", + "name": "default", "properties": { - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('cognitiveServicesUserRoleId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64))]" - ] + "tags": "[variables('resourceTags')]" + } }, { "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.log-analytics.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -69584,7 +74384,7 @@ "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.app-insights.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -69598,7 +74398,7 @@ "value": "[parameters('location')]" }, "workspaceResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "tags": { "value": "[parameters('tags')]" @@ -69611,7 +74411,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "4667471246975862151" + "templateHash": "12837854244259197798" } }, "parameters": { @@ -69674,6 +74474,13 @@ "metadata": { "description": "Flow type for Application Insights." } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Kind of Application Insights resource." + } } }, "resources": [ @@ -69683,7 +74490,7 @@ "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "kind": "web", + "kind": "[parameters('kind')]", "properties": { "Application_Type": "[parameters('applicationType')]", "Flow_Type": "[parameters('flowType')]", @@ -69735,30 +74542,34 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" - }, - "identityName": { - "value": "[variables('managedIdentityName')]" + "name": { + "value": "[variables('aiServicesName')]" }, "location": { - "value": "[parameters('location')]" + "value": "[parameters('azureAiServiceLocation')]" + }, + "principalIds": { + "value": [] + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "projectName": { + "value": "[variables('aiProjectName')]" }, "tags": { - "value": "[parameters('tags')]" + "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" } }, "template": { @@ -69768,74 +74579,160 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "14165903959794426055" + "templateHash": "8636926699738224009" } }, "parameters": { - "solutionName": { + "name": { "type": "string", "metadata": { - "description": "Solution name used for resource naming." + "description": "Required. Name of the AI Services account." } }, - "identityName": { + "location": { "type": "string", - "defaultValue": "[format('id-{0}', parameters('solutionName'))]", "metadata": { - "description": "Name of the managed identity." + "description": "Required. Azure region for the resource." } }, - "location": { + "principalIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." + } + }, + "publicNetworkAccess": { "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Azure region for the resource." + "description": "Optional. Whether public network access is allowed." } }, "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Tags to apply to the resource." + "description": "Optional. Tags to apply to the resource." + } + }, + "projectName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the AI Foundry project to create. If empty, no project is created." } } }, + "variables": { + "shouldCreateProject": "[not(empty(parameters('projectName')))]" + }, "resources": [ { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[parameters('identityName')]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-12-01", + "name": "[parameters('name')]", "location": "[parameters('location')]", - "tags": "[parameters('tags')]" + "tags": "[parameters('tags')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "sku": { + "name": "S0" + }, + "properties": { + "customSubDomainName": "[parameters('name')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "disableLocalAuth": true, + "allowProjectManagement": true, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" + } + } + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principalIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", + "properties": { + "principalId": "[parameters('principalIds')[copyIndex()]]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] + }, + { + "condition": "[variables('shouldCreateProject')]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('projectName'))]", + "location": "[parameters('location')]", + "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, + "tags": "[parameters('tags')]", + "properties": {}, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + ] } ], "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AI Services account." + }, + "value": "[parameters('name')]" + }, "resourceId": { "type": "string", "metadata": { - "description": "Resource ID of the managed identity." + "description": "The resource ID of the AI Services account." }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]" + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" }, - "principalId": { + "endpoint": { "type": "string", "metadata": { - "description": "Principal ID (object ID) of the managed identity." + "description": "The endpoint of the AI Services account." }, - "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').principalId]" + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2025-12-01').endpoint]" }, - "clientId": { + "systemAssignedPrincipalId": { "type": "string", "metadata": { - "description": "Client ID of the managed identity." + "description": "The principal ID of the system-assigned managed identity." }, - "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName')), '2023-01-31').clientId]" + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2025-12-01', 'full').identity.principalId]" }, - "name": { + "projectEndpoint": { "type": "string", "metadata": { - "description": "Name of the managed identity." + "description": "The AI Foundry project endpoint (empty if no project created)." + }, + "value": "[if(variables('shouldCreateProject'), reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('name'), parameters('projectName')), '2025-12-01').endpoints['AI Foundry API'], '')]" + }, + "projectName": { + "type": "string", + "metadata": { + "description": "The name of the AI Foundry project (empty if no project created)." }, - "value": "[parameters('identityName')]" + "value": "[if(variables('shouldCreateProject'), parameters('projectName'), '')]" } } } @@ -69844,26 +74741,30 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.model-deployment.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "solutionName": { - "value": "[variables('solutionSuffix')]" + "aiServicesAccountName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, - "name": { - "value": "[variables('containerRegistryName')]" + "deploymentName": { + "value": "[variables('modelDeploymentName')]" }, - "location": { - "value": "[parameters('location')]" + "modelName": { + "value": "[parameters('gptModelName')]" }, - "sku": "[if(parameters('enableRedundancy'), createObject('value', 'Premium'), createObject('value', 'Standard'))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "tags": { - "value": "[parameters('tags')]" + "modelVersion": { + "value": "[parameters('gptModelVersion')]" + }, + "skuName": { + "value": "[parameters('deploymentType')]" + }, + "skuCapacity": { + "value": "[parameters('gptDeploymentCapacity')]" } }, "template": { @@ -69873,103 +74774,78 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "17432455227529690473" + "templateHash": "18411757618261752815" } }, "parameters": { - "solutionName": { + "aiServicesAccountName": { "type": "string", "metadata": { - "description": "Solution name used for naming convention." + "description": "Required. Name of the parent AI Services account." } }, - "name": { + "deploymentName": { "type": "string", - "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", "metadata": { - "description": "Name of the container registry." + "description": "Required. Name for this model deployment." } }, - "location": { + "modelFormat": { "type": "string", + "defaultValue": "OpenAI", "metadata": { - "description": "Azure region for deployment." + "description": "Optional. Model format (e.g., OpenAI)." } }, - "tags": { - "type": "object", - "defaultValue": {}, + "modelName": { + "type": "string", "metadata": { - "description": "Resource tags." + "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." } }, - "sku": { + "modelVersion": { "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Basic", - "Standard", - "Premium" - ], + "defaultValue": "", "metadata": { - "description": "SKU for the container registry." + "description": "Optional. Model version. Empty string means latest." } }, - "adminUserEnabled": { - "type": "bool", - "defaultValue": false, + "raiPolicyName": { + "type": "string", + "defaultValue": "Microsoft.Default", "metadata": { - "description": "Enable admin user." + "description": "Optional. RAI policy name." } }, - "publicNetworkAccess": { + "skuName": { "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], "metadata": { - "description": "Public network access setting." + "description": "Required. SKU name (e.g., Standard, GlobalStandard)." } }, - "exportPolicyStatus": { - "type": "string", - "defaultValue": "enabled", + "skuCapacity": { + "type": "int", "metadata": { - "description": "Export policy status." + "description": "Required. SKU capacity (tokens per minute in thousands)." } } }, "resources": [ { - "type": "Microsoft.ContainerRegistry/registries", - "apiVersion": "2025-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-12-01", + "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", "properties": { - "adminUserEnabled": "[parameters('adminUserEnabled')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "dataEndpointEnabled": false, - "networkRuleBypassOptions": "AzureServices", - "policies": { - "exportPolicy": { - "status": "[parameters('exportPolicyStatus')]" - }, - "retentionPolicy": { - "status": "enabled", - "days": 7 - }, - "trustPolicy": { - "status": "disabled", - "type": "Notary" - } + "model": { + "format": "[parameters('modelFormat')]", + "name": "[parameters('modelName')]", + "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" }, - "zoneRedundancy": "Disabled" + "raiPolicyName": "[parameters('raiPolicyName')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacity": "[parameters('skuCapacity')]" } } ], @@ -69977,32 +74853,28 @@ "name": { "type": "string", "metadata": { - "description": "The name of the container registry." - }, - "value": "[parameters('name')]" - }, - "loginServer": { - "type": "string", - "metadata": { - "description": "The login server URL." + "description": "Name of the deployed model." }, - "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" + "value": "[parameters('deploymentName')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the container registry." + "description": "Resource ID of the model deployment." }, - "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" } } } - } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64))]" + ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.storage-account.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -70027,6 +74899,11 @@ } ] }, + "queues": { + "value": [ + "[variables('storageQueueName')]" + ] + }, "tags": { "value": "[parameters('tags')]" } @@ -70038,7 +74915,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "17696053432794478605" + "templateHash": "1152371270983236524" } }, "parameters": { @@ -70107,6 +74984,13 @@ "description": "Allow shared key access." } }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable hierarchical namespace (Data Lake Storage Gen2)." + } + }, "containers": { "type": "array", "defaultValue": [ @@ -70118,6 +75002,13 @@ "metadata": { "description": "Blob containers to create." } + }, + "queues": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Queue names to create." + } } }, "resources": [ @@ -70137,6 +75028,7 @@ "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", "minimumTlsVersion": "TLS1_2", "supportsHttpsTrafficOnly": true, + "isHnsEnabled": "[parameters('enableHierarchicalNamespace')]", "encryption": { "services": { "blob": { @@ -70173,6 +75065,27 @@ "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('name'), 'default')]" ] + }, + { + "condition": "[not(empty(parameters('queues')))]", + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "storageQueues", + "count": "[length(parameters('queues'))]" + }, + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2025-08-01", + "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', parameters('queues')[copyIndex()])]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('name'), 'default')]" + ] } ], "outputs": { @@ -70197,162 +75110,19 @@ }, "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.blob]" }, - "serviceEndpoints": { - "type": "object", - "metadata": { - "description": "All service endpoints." - }, - "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('aiServicesName')]" - }, - "location": { - "value": "[parameters('azureAiServiceLocation')]" - }, - "principalIds": { - "value": [] - }, - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "tags": { - "value": "[union(parameters('tags'), createObject('location', parameters('azureAiServiceLocation')))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "7594344478012985364" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services account." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Required. Azure region for the resource." - } - }, - "principalIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Principal IDs to assign Cognitive Services OpenAI User role." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether public network access is allowed." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to apply to the resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2024-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "AIServices", - "identity": { - "type": "SystemAssigned" - }, - "sku": { - "name": "S0" - }, - "properties": { - "customSubDomainName": "[parameters('name')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "disableLocalAuth": true, - "allowProjectManagement": true, - "networkAcls": { - "bypass": "AzureServices", - "defaultAction": "[if(equals(parameters('publicNetworkAccess'), 'Enabled'), 'Allow', 'Deny')]" - } - } - }, - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principalIds'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), parameters('principalIds')[copyIndex()], 'Cognitive Services OpenAI User')]", - "properties": { - "principalId": "[parameters('principalIds')[copyIndex()]]", - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AI Services account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the AI Services account." - }, - "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" - }, - "endpoint": { + "queueEndpoint": { "type": "string", "metadata": { - "description": "The endpoint of the AI Services account." + "description": "Primary queue endpoint." }, - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01').endpoint]" + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints.queue]" }, - "systemAssignedPrincipalId": { - "type": "string", + "serviceEndpoints": { + "type": "object", "metadata": { - "description": "The principal ID of the system-assigned managed identity." + "description": "All service endpoints." }, - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2024-10-01', 'full').identity.principalId]" + "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2025-08-01').primaryEndpoints]" } } } @@ -70361,28 +75131,60 @@ { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-model.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.cosmos-db-mongo.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "aiServicesAccountName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "solutionName": { + "value": "[variables('solutionSuffix')]" }, - "deploymentName": { - "value": "[variables('modelDeploymentName')]" + "name": { + "value": "[variables('cosmosDbName')]" }, - "modelName": { - "value": "[parameters('gptModelName')]" + "location": { + "value": "[parameters('location')]" }, - "skuName": { - "value": "GlobalStandard" + "tags": { + "value": "[parameters('tags')]" }, - "skuCapacity": { - "value": 10 - } + "databaseName": { + "value": "[variables('cosmosDatabaseName')]" + }, + "collections": { + "value": [ + { + "name": "[variables('cosmosContainerName')]", + "shardKey": { + "id": "Hash" + }, + "indexes": [ + { + "key": { + "keys": [ + "_id" + ] + } + } + ] + } + ] + }, + "serverVersion": { + "value": "7.0" + }, + "consistencyLevel": { + "value": "Session" + }, + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" + }, + "enableAutomaticFailover": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -70391,107 +75193,218 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "18411757618261752815" + "templateHash": "16959142942271052833" } }, "parameters": { - "aiServicesAccountName": { + "solutionName": { "type": "string", "metadata": { - "description": "Required. Name of the parent AI Services account." + "description": "Solution name suffix used to derive the resource name." } }, - "deploymentName": { + "name": { "type": "string", + "defaultValue": "[format('cosmos-{0}', parameters('solutionName'))]", "metadata": { - "description": "Required. Name for this model deployment." + "description": "Name of the Cosmos DB account." } }, - "modelFormat": { + "location": { "type": "string", - "defaultValue": "OpenAI", "metadata": { - "description": "Optional. Model format (e.g., OpenAI)." + "description": "Azure region for the resource." } }, - "modelName": { + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to apply to the resource." + } + }, + "databaseName": { "type": "string", + "defaultValue": "default", "metadata": { - "description": "Required. Model name (e.g., gpt-4o, text-embedding-ada-002)." + "description": "MongoDB database name." } }, - "modelVersion": { + "collections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "MongoDB collections to create." + } + }, + "serverVersion": { "type": "string", - "defaultValue": "", + "defaultValue": "7.0", + "allowedValues": [ + "4.2", + "5.0", + "6.0", + "7.0" + ], "metadata": { - "description": "Optional. Model version. Empty string means latest." + "description": "MongoDB server version." } }, - "raiPolicyName": { + "consistencyLevel": { "type": "string", - "defaultValue": "Microsoft.Default", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], "metadata": { - "description": "Optional. RAI policy name." + "description": "Default consistency level." } }, - "skuName": { + "enableAnalyticalStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable analytical storage (Synapse Link)." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable zone redundancy." + } + }, + "enableAutomaticFailover": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable automatic failover." + } + }, + "haLocation": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. SKU name (e.g., Standard, GlobalStandard)." + "description": "HA paired region for multi-region failover." } }, - "skuCapacity": { - "type": "int", + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", "metadata": { - "description": "Required. SKU capacity (tokens per minute in thousands)." + "description": "Public network access setting." } } }, "resources": [ { - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-12-01", - "name": "[format('{0}/{1}', parameters('aiServicesAccountName'), parameters('deploymentName'))]", + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2025-10-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "MongoDB", "properties": { - "model": { - "format": "[parameters('modelFormat')]", - "name": "[parameters('modelName')]", - "version": "[if(not(empty(parameters('modelVersion'))), parameters('modelVersion'), null())]" - }, - "raiPolicyName": "[parameters('raiPolicyName')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacity": "[parameters('skuCapacity')]" + "consistencyPolicy": { + "defaultConsistencyLevel": "[parameters('consistencyLevel')]" + }, + "locations": "[if(and(parameters('zoneRedundant'), not(empty(parameters('haLocation')))), createArray(createObject('locationName', parameters('location'), 'failoverPriority', 0, 'isZoneRedundant', true()), createObject('locationName', parameters('haLocation'), 'failoverPriority', 1, 'isZoneRedundant', true())), createArray(createObject('locationName', parameters('location'), 'failoverPriority', 0, 'isZoneRedundant', parameters('zoneRedundant'))))]", + "databaseAccountOfferType": "Standard", + "enableAutomaticFailover": "[parameters('enableAutomaticFailover')]", + "enableMultipleWriteLocations": false, + "apiProperties": { + "serverVersion": "[parameters('serverVersion')]" + }, + "enableAnalyticalStorage": "[parameters('enableAnalyticalStorage')]", + "capabilities": [ + { + "name": "EnableMongo" + } + ], + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" } + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2025-10-15", + "name": "[format('{0}/{1}', parameters('name'), parameters('databaseName'))]", + "properties": { + "resource": { + "id": "[parameters('databaseName')]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + ] + }, + { + "copy": { + "name": "mongoCollections", + "count": "[length(parameters('collections'))]" + }, + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2025-10-15", + "name": "[format('{0}/{1}/{2}', parameters('name'), parameters('databaseName'), parameters('collections')[copyIndex()].name)]", + "properties": { + "resource": { + "id": "[parameters('collections')[copyIndex()].name]", + "shardKey": "[coalesce(tryGet(parameters('collections')[copyIndex()], 'shardKey'), createObject())]", + "indexes": "[coalesce(tryGet(parameters('collections')[copyIndex()], 'indexes'), createArray(createObject('key', createObject('keys', createArray('_id')))))]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('name'), parameters('databaseName'))]" + ] } ], "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of the Cosmos DB account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "Name of the deployed model." + "description": "Name of the Cosmos DB account." }, - "value": "[parameters('deploymentName')]" + "value": "[parameters('name')]" }, - "resourceId": { + "connectionString": { "type": "string", "metadata": { - "description": "Resource ID of the model deployment." + "description": "MongoDB connection string (without credentials — use Key Vault for secrets)." }, - "value": "[resourceId('Microsoft.CognitiveServices/accounts/deployments', parameters('aiServicesAccountName'), parameters('deploymentName'))]" + "value": "[format('mongodb+srv://{0}.mongo.cosmos.azure.com:443/?ssl=true&retrywrites=false&maxIdleTimeMS=120000', parameters('name'))]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "Endpoint of the Cosmos DB account." + }, + "value": "[format('https://{0}.mongo.cosmos.azure.com:443/', parameters('name'))]" + }, + "databaseName": { + "type": "string", + "metadata": { + "description": "Database name." + }, + "value": "[parameters('databaseName')]" } } } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]" - ] + } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.app-configuration.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -70502,14 +75415,75 @@ "value": "[variables('solutionSuffix')]" }, "name": { - "value": "[variables('aiSearchName')]" + "value": "[variables('appConfigurationName')]" }, "location": { "value": "[parameters('location')]" }, - "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", - "partitionCount": "[if(parameters('enableScalability'), createObject('value', 2), createObject('value', 1))]", - "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "keyValues": { + "value": [ + { + "name": "APP_AZURE_OPENAI_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AZURE_OPENAI_MODEL", + "value": "[parameters('gptModelName')]" + }, + { + "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_AI_PROJECT_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.projectEndpoint.value]" + }, + { + "name": "APP_COSMOS_DB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value]" + }, + { + "name": "APP_COSMOS_DB_NAME", + "value": "[variables('cosmosDatabaseName')]" + }, + { + "name": "APP_COSMOS_DB_CONTAINER", + "value": "[variables('cosmosContainerName')]" + }, + { + "name": "APP_STORAGE_ACCOUNT_NAME", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" + }, + { + "name": "APP_STORAGE_BLOB_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.blobEndpoint.value]" + }, + { + "name": "APP_STORAGE_QUEUE_ENDPOINT", + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" + }, + { + "name": "APP_STORAGE_CONTAINER_NAME", + "value": "[variables('storageContainerName')]" + }, + { + "name": "APP_WORKFLOW_APP_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "APP_API_ENDPOINT", + "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + }, + { + "name": "AZURE_OPENAI_API_VERSION", + "value": "2025-03-01-preview" + }, + { + "name": "AZURE_TRACING_ENABLED", + "value": "True" + } + ] + }, "tags": { "value": "[parameters('tags')]" } @@ -70521,22 +75495,21 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "714050788324647491" + "templateHash": "17000481054877854952" } }, "parameters": { "solutionName": { "type": "string", - "minLength": 3, "metadata": { - "description": "Solution name suffix used to derive the resource name." + "description": "Solution name used for naming convention." } }, "name": { "type": "string", - "defaultValue": "[format('srch-{0}', parameters('solutionName'))]", + "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", "metadata": { - "description": "Optional. Override name for the search service. Defaults to srch-{solutionName}." + "description": "Name of the App Configuration store." } }, "location": { @@ -70552,302 +75525,99 @@ "description": "Tags to apply to the resource." } }, - "skuName": { - "type": "string", - "defaultValue": "basic", - "allowedValues": [ - "free", - "basic", - "standard", - "standard2", - "standard3", - "storage_optimized_l1", - "storage_optimized_l2" - ], - "metadata": { - "description": "SKU name for the search service." - } - }, - "replicaCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of replicas." - } - }, - "partitionCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of partitions." - } - }, - "hostingMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "HighDensity" - ], - "metadata": { - "description": "Hosting mode." - } - }, - "semanticSearch": { + "sku": { "type": "string", - "defaultValue": "free", + "defaultValue": "Standard", "allowedValues": [ - "disabled", - "free", - "standard" + "Free", + "Standard" ], "metadata": { - "description": "Semantic search tier." + "description": "SKU for the configuration store." } }, "disableLocalAuth": { "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Whether to disable local authentication." - } - }, - "managedIdentityType": { - "type": "string", - "defaultValue": "SystemAssigned", + "defaultValue": false, "metadata": { - "description": "Managed identity type for the search service." + "description": "Disable local (key-based) authentication." } }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", + "keyValues": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Public network access setting." + "description": "Key-value pairs to store in the configuration." } } }, "resources": [ { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2023-03-01", "name": "[parameters('name')]", "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "sku": { - "name": "[parameters('skuName')]" + "name": "[parameters('sku')]" + }, + "properties": { + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "publicNetworkAccess": "Enabled" } }, { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2025-04-01", - "name": "searchServiceUpdate", + "copy": { + "name": "configurationKeyValues", + "count": "[length(parameters('keyValues'))]" + }, + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "skuName": { - "value": "[parameters('skuName')]" - }, - "replicaCount": { - "value": "[parameters('replicaCount')]" - }, - "partitionCount": { - "value": "[parameters('partitionCount')]" - }, - "hostingMode": { - "value": "[parameters('hostingMode')]" - }, - "semanticSearch": { - "value": "[parameters('semanticSearch')]" - }, - "disableLocalAuth": { - "value": "[parameters('disableLocalAuth')]" - }, - "managedIdentityType": { - "value": "[parameters('managedIdentityType')]" - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "3683977219901178221" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the existing AI Search service." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The Azure region of the search service." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to the resource." - } - }, - "skuName": { - "type": "string", - "defaultValue": "basic", - "metadata": { - "description": "SKU name for the search service." - } - }, - "replicaCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of replicas." - } - }, - "partitionCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Number of partitions." - } - }, - "hostingMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "HighDensity" - ], - "metadata": { - "description": "Hosting mode." - } - }, - "semanticSearch": { - "type": "string", - "defaultValue": "free", - "metadata": { - "description": "Semantic search tier." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Whether to disable local authentication." - } - }, - "managedIdentityType": { - "type": "string", - "defaultValue": "SystemAssigned", - "metadata": { - "description": "Managed identity type for the search service." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Public network access setting." - } - } - }, - "resources": [ - { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": { - "type": "[parameters('managedIdentityType')]" - }, - "properties": { - "replicaCount": "[parameters('replicaCount')]", - "partitionCount": "[parameters('partitionCount')]", - "hostingMode": "[parameters('hostingMode')]", - "semanticSearch": "[parameters('semanticSearch')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]" - } - } - ], - "outputs": { - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the AI Search system-assigned managed identity." - }, - "value": "[reference(resourceId('Microsoft.Search/searchServices', parameters('name')), '2025-05-01', 'full').identity.principalId]" - } - } - } + "value": "[parameters('keyValues')[copyIndex()].value]" }, "dependsOn": [ - "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" ] } ], "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the AI Search service." - }, - "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "Name of the AI Search service." + "description": "The name of the App Configuration store." }, "value": "[parameters('name')]" }, "endpoint": { "type": "string", "metadata": { - "description": "Endpoint URL of the AI Search service." + "description": "The endpoint of the App Configuration store." }, - "value": "[format('https://{0}.search.windows.net', parameters('name'))]" + "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" }, - "identityPrincipalId": { + "resourceId": { "type": "string", "metadata": { - "description": "System-assigned identity principal ID." + "description": "The resource ID of the App Configuration store." }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', 'searchServiceUpdate'), '2025-04-01').outputs.systemAssignedMIPrincipalId.value]" + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" } } } - } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.cosmos-db-mongo.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64))]" + ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-registry.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -70858,15 +75628,13 @@ "value": "[variables('solutionSuffix')]" }, "name": { - "value": "[variables('containerAppEnvironmentName')]" + "value": "[variables('containerRegistryName')]" }, "location": { "value": "[parameters('location')]" }, - "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", - "zoneRedundant": { - "value": "[parameters('enableRedundancy')]" - }, + "sku": "[if(or(parameters('enableRedundancy'), parameters('enablePrivateNetworking')), createObject('value', 'Premium'), createObject('value', 'Standard'))]", + "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", "tags": { "value": "[parameters('tags')]" } @@ -70878,7 +75646,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "17265155980354931238" + "templateHash": "4396841227323887436" } }, "parameters": { @@ -70890,9 +75658,9 @@ }, "name": { "type": "string", - "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", + "defaultValue": "[replace(format('cr{0}', parameters('solutionName')), '-', '')]", "metadata": { - "description": "Name of the Container Apps Environment." + "description": "Name of the container registry." } }, "location": { @@ -70908,44 +75676,53 @@ "description": "Resource tags." } }, - "logAnalyticsWorkspaceResourceId": { + "sku": { "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], "metadata": { - "description": "Resource ID of the Log Analytics workspace." + "description": "SKU for the container registry." } }, - "infrastructureSubnetId": { - "type": "string", - "defaultValue": "", + "adminUserEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Subnet resource ID for VNet integration (optional)." + "description": "Enable admin user." } }, - "zoneRedundant": { - "type": "bool", - "defaultValue": false, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], "metadata": { - "description": "Enable zone redundancy." + "description": "Public network access setting." } } }, "resources": [ { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2024-03-01", + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2025-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, "properties": { - "appLogsConfiguration": { - "destination": "log-analytics", - "logAnalyticsConfiguration": { - "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", - "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" - } - }, - "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", - "zoneRedundant": "[parameters('zoneRedundant')]" + "adminUserEnabled": "[parameters('adminUserEnabled')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "dataEndpointEnabled": false, + "networkRuleBypassOptions": "AzureServices", + "zoneRedundancy": "Disabled" } } ], @@ -70953,42 +75730,32 @@ "name": { "type": "string", "metadata": { - "description": "The name of the Container Apps Environment." + "description": "The name of the container registry." }, "value": "[parameters('name')]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container Apps Environment." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" - }, - "defaultDomain": { + "loginServer": { "type": "string", "metadata": { - "description": "The default domain of the Container Apps Environment." + "description": "The login server URL." }, - "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2025-04-01').loginServer]" }, - "staticIp": { + "resourceId": { "type": "string", "metadata": { - "description": "The static IP address of the Container Apps Environment." + "description": "The resource ID of the container registry." }, - "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" } } } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', variables('solutionSuffix')), 64))]" - ] + } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.app-config.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -70999,82 +75766,14 @@ "value": "[variables('solutionSuffix')]" }, "name": { - "value": "[variables('appConfigurationName')]" + "value": "[variables('containerAppEnvironmentName')]" }, "location": { "value": "[parameters('location')]" }, - "keyValues": { - "value": [ - { - "name": "APP_AZURE_OPENAI_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" - }, - { - "name": "APP_AZURE_OPENAI_MODEL", - "value": "[parameters('gptModelName')]" - }, - { - "name": "APP_CONTENT_UNDERSTANDING_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" - }, - { - "name": "APP_AI_PROJECT_ENDPOINT", - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName')), '2025-12-01').endpoints['AI Foundry API']]" - }, - { - "name": "APP_COSMOS_DB_ENDPOINT", - "value": "[variables('cosmosDbEndpoint')]" - }, - { - "name": "APP_COSMOS_DB_NAME", - "value": "[variables('cosmosDatabaseName')]" - }, - { - "name": "APP_COSMOS_DB_CONTAINER", - "value": "[variables('cosmosContainerName')]" - }, - { - "name": "APP_STORAGE_ACCOUNT_NAME", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" - }, - { - "name": "APP_STORAGE_BLOB_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.blobEndpoint.value]" - }, - { - "name": "APP_STORAGE_QUEUE_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.serviceEndpoints.value.queue]" - }, - { - "name": "APP_STORAGE_CONTAINER_NAME", - "value": "[variables('storageContainerName')]" - }, - { - "name": "APP_AI_SEARCH_ENDPOINT", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value]" - }, - { - "name": "APP_AI_SEARCH_INDEX", - "value": "content-index" - }, - { - "name": "APP_WORKFLOW_APP_ENDPOINT", - "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorWorkflowName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" - }, - { - "name": "APP_API_ENDPOINT", - "value": "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "2025-03-01-preview" - }, - { - "name": "AZURE_TRACING_ENABLED", - "value": "True" - } - ] + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), createObject('value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value), createObject('value', ''))]", + "zoneRedundant": { + "value": "[parameters('enableRedundancy')]" }, "tags": { "value": "[parameters('tags')]" @@ -71087,7 +75786,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "18286182317157861590" + "templateHash": "13592927098539789837" } }, "parameters": { @@ -71099,119 +75798,118 @@ }, "name": { "type": "string", - "defaultValue": "[format('appcs-{0}', parameters('solutionName'))]", + "defaultValue": "[format('cae-{0}', parameters('solutionName'))]", "metadata": { - "description": "Name of the App Configuration store." + "description": "Name of the Container Apps Environment." } }, "location": { "type": "string", "metadata": { - "description": "Azure region for the resource." + "description": "Azure region for deployment." } }, "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Tags to apply to the resource." + "description": "Resource tags." } }, - "sku": { + "logAnalyticsWorkspaceResourceId": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Standard" - ], "metadata": { - "description": "SKU for the configuration store." + "description": "Resource ID of the Log Analytics workspace." } }, - "disableLocalAuth": { + "infrastructureSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Subnet resource ID for VNet integration (optional)." + } + }, + "zoneRedundant": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Disable local (key-based) authentication." + "description": "Enable zone redundancy." } }, - "keyValues": { + "workloadProfiles": { "type": "array", - "defaultValue": [], + "defaultValue": [ + { + "name": "Consumption", + "workloadProfileType": "Consumption" + } + ], "metadata": { - "description": "Key-value pairs to store in the configuration." + "description": "Workload profiles configuration (e.g., Consumption or dedicated D4 profiles)." } } }, "resources": [ { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2023-03-01", + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2024-03-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, "properties": { - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "publicNetworkAccess": "Enabled" + "appLogsConfiguration": { + "destination": "log-analytics", + "logAnalyticsConfiguration": { + "customerId": "[reference(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').customerId]", + "sharedKey": "[listKeys(parameters('logAnalyticsWorkspaceResourceId'), '2023-09-01').primarySharedKey]" + } + }, + "vnetConfiguration": "[if(empty(parameters('infrastructureSubnetId')), null(), createObject('infrastructureSubnetId', parameters('infrastructureSubnetId')))]", + "workloadProfiles": "[parameters('workloadProfiles')]", + "zoneRedundant": "[parameters('zoneRedundant')]" } - }, - { - "copy": { - "name": "configurationKeyValues", - "count": "[length(parameters('keyValues'))]" - }, - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2023-03-01", - "name": "[format('{0}/{1}', parameters('name'), parameters('keyValues')[copyIndex()].name)]", - "properties": { - "value": "[parameters('keyValues')[copyIndex()].value]" - }, - "dependsOn": [ - "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" - ] } ], "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the App Configuration store." + "description": "The name of the Container Apps Environment." }, "value": "[parameters('name')]" }, - "endpoint": { + "resourceId": { "type": "string", "metadata": { - "description": "The endpoint of the App Configuration store." + "description": "The resource ID of the Container Apps Environment." }, - "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name')), '2023-03-01').endpoint]" + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" }, - "resourceId": { + "defaultDomain": { "type": "string", "metadata": { - "description": "The resource ID of the App Configuration store." + "description": "The default domain of the Container Apps Environment." }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('name'))]" + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').defaultDomain]" + }, + "staticIp": { + "type": "string", + "metadata": { + "description": "The static IP address of the Container Apps Environment." + }, + "value": "[reference(resourceId('Microsoft.App/managedEnvironments', parameters('name')), '2024-03-01').staticIp]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiServicesName'), variables('aiProjectName'))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-search.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbName'))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.storage-account.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.log-analytics.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-app.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -71225,7 +75923,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "disableIngress": { "value": true @@ -71234,31 +75932,21 @@ "value": [ { "name": "[variables('contentProcessorAppName')]", - "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessor:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 4, "memory": "8Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessor')))]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "scaleSettings": { "value": { "minReplicas": "[if(parameters('enableScalability'), 2, 1)]", @@ -71475,17 +76163,16 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-api.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-api.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -71499,7 +76186,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "ingressExternal": { "value": true @@ -71511,32 +76198,22 @@ "value": [ { "name": "[variables('contentProcessorApiName')]", - "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessorapi:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 2, "memory": "4Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorAPI')))]", "probes": "[variables('apiProbes')]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "scaleSettings": { "value": { "minReplicas": 0, @@ -71753,17 +76430,16 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-web.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-web.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -71777,7 +76453,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "ingressExternal": { "value": true @@ -71789,35 +76465,25 @@ "value": [ { "name": "[variables('contentProcessorWebName')]", - "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessorweb:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 2, "memory": "4Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'APP_API_BASE_URL', 'value', format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))), createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWeb')))]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "corsPolicy": { "value": { "allowedOrigins": [ - "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value))]" + "[format('https://{0}', format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value))]" ], "allowedMethods": [ "GET", @@ -72047,17 +76713,16 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" ] }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)]", + "name": "[take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -72071,7 +76736,7 @@ "value": "[parameters('location')]" }, "environmentResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "ingressExternal": { "value": true @@ -72083,31 +76748,21 @@ "value": [ { "name": "[variables('contentProcessorWorkflowName')]", - "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", + "image": "[format('{0}/contentprocessorworkflow:{1}', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), parameters('imageTag'))]", "resources": { "cpu": 2, "memory": "4Gi" }, - "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" + "env": "[concat(createArray(createObject('name', 'APP_CONFIG_ENDPOINT', 'value', reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.endpoint.value), createObject('name', 'APP_ENV', 'value', 'prod'), createObject('name', 'APP_LOGGING_LEVEL', 'value', 'INFO'), createObject('name', 'AZURE_PACKAGE_LOGGING_LEVEL', 'value', 'WARNING'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', if(parameters('enableMonitoring'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.connectionString.value, ''))), createArray(createObject('name', 'OTEL_SERVICE_NAME', 'value', 'ContentProcessorWorkflow')))]" } ] }, "managedIdentities": { "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - ] + "systemAssigned": true } }, - "registries": { - "value": [ - { - "server": "[if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint'))]", - "identity": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" - } - ] - }, + "registries": "[if(variables('useExternalRegistry'), createObject('value', null()), createObject('value', createArray(createObject('server', if(empty(parameters('containerRegistryEndpoint')), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value, parameters('containerRegistryEndpoint')), 'identity', 'system'))))]", "scaleSettings": { "value": { "minReplicas": 0, @@ -72324,124 +76979,524 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-config.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64))]", - "[resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64))]" + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-configuration.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.app-insights.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('module.role-assignments.{0}', parameters('solutionName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "solutionName": { + "value": "[variables('solutionSuffix')]" + }, + "containerRegistryName": { + "value": "[variables('containerRegistryName')]" + }, + "storageAccountName": { + "value": "[variables('storageAccountName')]" + }, + "appConfigurationName": { + "value": "[variables('appConfigurationName')]" + }, + "aiServicesName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" + }, + "managedIdentityPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorAppPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorApiPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-api.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorWebPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-web.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + }, + "contentProcessorWorkflowPrincipalId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.42.1.51946", + "templateHash": "12613756564324619461" + } + }, + "parameters": { + "solutionName": { + "type": "string", + "metadata": { + "description": "Solution name suffix for generating unique role assignment GUIDs." + } + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "Name of the Container Registry." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Name of the Storage Account." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Name of the App Configuration store." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Name of the AI Services account." + } + }, + "managedIdentityPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the system-assigned identity (for ACR pull)." + } + }, + "contentProcessorAppPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor App." + } + }, + "contentProcessorApiPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor API." + } + }, + "contentProcessorWebPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor Web." + } + }, + "contentProcessorWorkflowPrincipalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the Content Processor Workflow." + } + } + }, + "variables": { + "roleDefinitions": { + "acrPull": "7f951dda-4ed3-4680-a7ca-43fe172d538d", + "storageBlobDataContributor": "ba92f5b4-2d11-453d-a403-e96b0029c9fe", + "storageQueueDataContributor": "974c5e8b-45b9-4653-ba55-5f855dd0fb88", + "appConfigurationDataReader": "516239f1-63e1-4d78-a4de-a74fb236a071", + "cognitiveServicesOpenAiUser": "5e0bd9bd-7b93-4f28-af87-19fc36ad61bd", + "cognitiveServicesUser": "a97b65f3-24c7-4388-baec-2e87135dc908", + "azureAiDeveloper": "64702f94-c441-49e6-a78b-ef80e0188fee" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]", + "name": "[guid(parameters('containerRegistryName'), parameters('solutionName'), 'acr-pull')]", + "properties": { + "principalId": "[parameters('managedIdentityPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').acrPull)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'app', 'blob')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'api', 'blob')]", + "properties": { + "principalId": "[parameters('contentProcessorApiPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'workflow', 'blob')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'app', 'queue')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageQueueDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'api', 'queue')]", + "properties": { + "principalId": "[parameters('contentProcessorApiPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageQueueDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]", + "name": "[guid(parameters('storageAccountName'), 'workflow', 'queue')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageQueueDataContributor)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'app', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'api', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorApiPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'web', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorWebPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', parameters('appConfigurationName'))]", + "name": "[guid(parameters('appConfigurationName'), 'workflow', 'appconfig')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').appConfigurationDataReader)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'app', 'openai-user')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesOpenAiUser)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'workflow', 'openai-user')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesOpenAiUser)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'app', 'ai-developer')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').azureAiDeveloper)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'workflow', 'ai-developer')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').azureAiDeveloper)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'app', 'cog-user')]", + "properties": { + "principalId": "[parameters('contentProcessorAppPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesUser)]" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName'))]", + "name": "[guid(parameters('aiServicesName'), 'workflow', 'cog-user')]", + "properties": { + "principalId": "[parameters('contentProcessorWorkflowPrincipalId')]", + "principalType": "ServicePrincipal", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').cognitiveServicesUser)]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-api.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-web.{0}', parameters('solutionName')), 64))]", + "[resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64))]" ] } ], "outputs": { "SOLUTION_NAME": { "type": "string", + "metadata": { + "description": "The solution name." + }, "value": "[parameters('solutionName')]" }, "CONTAINER_WEB_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-web.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for Web App." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-web.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_API_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-api.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for API." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-api.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WEB_APP_FQDN": { "type": "string", - "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + "metadata": { + "description": "The FQDN of the Container App Web." + }, + "value": "[format('{0}.{1}', variables('contentProcessorWebName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, "CONTAINER_API_APP_FQDN": { "type": "string", - "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.defaultDomain.value)]" + "metadata": { + "description": "The FQDN of the Container App API." + }, + "value": "[format('{0}.{1}', variables('contentProcessorApiName'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-app-environment.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.defaultDomain.value)]" }, "CONTAINER_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-app.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for APP." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-workflow.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Container App used for Workflow." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-workflow.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_APP_USER_IDENTITY_ID": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.resourceId.value]" + "metadata": { + "description": "The system-assigned identity resource ID used for the Container App." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.resourceId.value]" }, "CONTAINER_APP_USER_PRINCIPAL_ID": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.managed-identity.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.principalId.value]" + "metadata": { + "description": "The system-assigned identity Principal ID used for the Container App." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.content-processor-app.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]" }, "CONTAINER_REGISTRY_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the Azure Container Registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "CONTAINER_REGISTRY_LOGIN_SERVER": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.loginServer.value]" + "metadata": { + "description": "The login server of the Azure Container Registry." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.container-registry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.loginServer.value]" }, "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', variables('solutionSuffix')), 64)), '2025-04-01').outputs.name.value]" + "metadata": { + "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ai-foundry.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]" }, "AZURE_RESOURCE_GROUP": { "type": "string", + "metadata": { + "description": "The resource group the resources were deployed into." + }, "value": "[resourceGroup().name]" } } } } } - ], + }, "outputs": { "SOLUTION_NAME": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.SOLUTION_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.SOLUTION_NAME.value)]" + "metadata": { + "description": "Solution name output from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.SOLUTION_NAME.value, reference('bicepDeployment').outputs.SOLUTION_NAME.value)]" }, "CONTAINER_WEB_APP_NAME": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_NAME.value)]" + "metadata": { + "description": "Container web app name from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_WEB_APP_NAME.value, reference('bicepDeployment').outputs.CONTAINER_WEB_APP_NAME.value)]" }, "CONTAINER_API_APP_NAME": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_NAME.value)]" + "metadata": { + "description": "Container API app name from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_API_APP_NAME.value, reference('bicepDeployment').outputs.CONTAINER_API_APP_NAME.value)]" }, "CONTAINER_WEB_APP_FQDN": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_FQDN.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WEB_APP_FQDN.value)]" + "metadata": { + "description": "Container web app FQDN from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_WEB_APP_FQDN.value, reference('bicepDeployment').outputs.CONTAINER_WEB_APP_FQDN.value)]" }, "CONTAINER_API_APP_FQDN": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_FQDN.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_API_APP_FQDN.value)]" + "metadata": { + "description": "Container API app FQDN from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_API_APP_FQDN.value, reference('bicepDeployment').outputs.CONTAINER_API_APP_FQDN.value)]" }, "CONTAINER_APP_NAME": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_NAME.value)]" + "metadata": { + "description": "Container app name from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_APP_NAME.value, reference('bicepDeployment').outputs.CONTAINER_APP_NAME.value)]" }, "CONTAINER_WORKFLOW_APP_NAME": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WORKFLOW_APP_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_WORKFLOW_APP_NAME.value)]" + "metadata": { + "description": "Container workflow app name from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_WORKFLOW_APP_NAME.value, reference('bicepDeployment').outputs.CONTAINER_WORKFLOW_APP_NAME.value)]" }, "CONTAINER_APP_USER_IDENTITY_ID": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_IDENTITY_ID.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_IDENTITY_ID.value)]" + "metadata": { + "description": "Container app user-assigned identity resource ID from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_APP_USER_IDENTITY_ID.value, reference('bicepDeployment').outputs.CONTAINER_APP_USER_IDENTITY_ID.value)]" }, "CONTAINER_APP_USER_PRINCIPAL_ID": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value)]" + "metadata": { + "description": "Container app user-assigned identity principal ID from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value, reference('bicepDeployment').outputs.CONTAINER_APP_USER_PRINCIPAL_ID.value)]" }, "CONTAINER_REGISTRY_NAME": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_NAME.value)]" + "metadata": { + "description": "Container registry name from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_REGISTRY_NAME.value, reference('bicepDeployment').outputs.CONTAINER_REGISTRY_NAME.value)]" }, "CONTAINER_REGISTRY_LOGIN_SERVER": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value)]" + "metadata": { + "description": "Container registry login server from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value, reference('bicepDeployment').outputs.CONTAINER_REGISTRY_LOGIN_SERVER.value)]" }, "CONTENT_UNDERSTANDING_ACCOUNT_NAME": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value)]" + "metadata": { + "description": "Content Understanding account name from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value, reference('bicepDeployment').outputs.CONTENT_UNDERSTANDING_ACCOUNT_NAME.value)]" }, "AZURE_RESOURCE_GROUP": { "type": "string", - "value": "[if(variables('isAvm'), reference(resourceId('Microsoft.Resources/deployments', take(format('module.avm.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.AZURE_RESOURCE_GROUP.value, reference(resourceId('Microsoft.Resources/deployments', take(format('module.bicep.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.AZURE_RESOURCE_GROUP.value)]" + "metadata": { + "description": "Azure resource group output from the selected deployment flavor." + }, + "value": "[if(variables('isAvm'), reference('avmDeployment').outputs.AZURE_RESOURCE_GROUP.value, reference('bicepDeployment').outputs.AZURE_RESOURCE_GROUP.value)]" } } } \ No newline at end of file